blob: e472a8aea396ee7e6e84f263e8cf38cd6b5b2791 [file] [log] [blame]
/*
* Copyright 2023 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef skgpu_graphite_VulkanGraphicsPipeline_DEFINED
#define skgpu_graphite_VulkanGraphicsPipeline_DEFINED
#include "include/core/SkRefCnt.h"
#include "include/core/SkSpan.h"
#include "include/gpu/vk/VulkanTypes.h"
#include "include/private/base/SkTArray.h"
#include "src/gpu/Blend.h"
#include "src/gpu/graphite/DrawTypes.h"
#include "src/gpu/graphite/GraphicsPipeline.h"
#include "src/gpu/graphite/vk/VulkanGraphiteUtils.h"
#include "src/gpu/graphite/vk/VulkanSampler.h"
namespace SkSL {
class Compiler;
}
namespace skgpu::graphite {
class Attribute;
class GraphicsPipelineDesc;
class RuntimeEffectDictionary;
class VulkanResourceProvider;
class VulkanSharedContext;
struct RenderPassDesc;
class TextureInfo;
class VulkanRenderPass;
// VulkanProgramInfo owns the underlying vulkan objects and are deleted automatically.
class VulkanProgramInfo {
public:
~VulkanProgramInfo();
static std::unique_ptr<VulkanProgramInfo> Make(const VulkanSharedContext* sharedContext) {
SkASSERT(sharedContext);
return std::unique_ptr<VulkanProgramInfo>(new VulkanProgramInfo(sharedContext));
}
VkShaderModule vs() const { return fVS; }
VkShaderModule fs() const { return fFS; }
VkPipelineLayout layout() const { return fLayout; }
// Relinquishes ownership of the VkPipelineLayout and no longer holds a pointer to it.
VkPipelineLayout releaseLayout() {
VkPipelineLayout layout = fLayout;
fLayout = VK_NULL_HANDLE;
return layout;
}
// The modules and layout can be set at most once
bool setVertexShader(VkShaderModule vs) {
SkASSERT(fVS == VK_NULL_HANDLE);
fVS = vs;
return fVS != VK_NULL_HANDLE;
}
bool setFragmentShader(VkShaderModule fs) {
SkASSERT(fFS == VK_NULL_HANDLE);
fFS = fs;
return fFS != VK_NULL_HANDLE;
}
bool setLayout(VkPipelineLayout layout) {
SkASSERT(fLayout == VK_NULL_HANDLE);
fLayout = layout;
return fLayout != VK_NULL_HANDLE;
}
private:
VulkanProgramInfo(const VulkanProgramInfo&) = delete;
explicit VulkanProgramInfo(const VulkanSharedContext* sharedContext)
: fSharedContext(sharedContext) {}
const VulkanSharedContext* fSharedContext; // For cleanup
VkShaderModule fVS = VK_NULL_HANDLE;
VkShaderModule fFS = VK_NULL_HANDLE;
VkPipelineLayout fLayout = VK_NULL_HANDLE;
};
class VulkanGraphicsPipeline final : public GraphicsPipeline {
public:
inline static constexpr unsigned int kRenderStepUniformBufferIndex = 0;
inline static constexpr unsigned int kPaintUniformBufferIndex = 1;
inline static constexpr unsigned int kGradientBufferIndex = 2;
inline static constexpr unsigned int kNumUniformBuffers = 3;
// For now, rigidly assign all descriptor types to be at statically-defined set indices.
// TODO(b/274762935): Make the bindings and descriptor set organization more flexible.
inline static constexpr unsigned int kDstAsInputDescSetIndex = 0;
inline static constexpr unsigned int kUniformBufferDescSetIndex = 1;
inline static constexpr unsigned int kTextureBindDescSetIndex = 2;
inline static constexpr unsigned int kLoadMsaaFromResolveInputDescSetIndex = 3;
inline static constexpr unsigned int kMaxNumDescSets = 4;
inline static constexpr unsigned int kStaticDataBufferIndex = 0;
inline static constexpr unsigned int kAppendDataBufferIndex = 1;
inline static constexpr unsigned int kNumInputBuffers = 2;
// Define a static DescriptorData to represent input attachments which have the same values
// across all pipelines (we currently only ever use one input attachment within a set).
inline static const DescriptorData kInputAttachmentDescriptor = {
DescriptorType::kInputAttachment, /*count=*/1,
/*bindingIdx=*/0, // We only expect to encounter one input attachment
PipelineStageFlags::kFragmentShader};
static sk_sp<VulkanGraphicsPipeline> Make(const VulkanSharedContext*,
VulkanResourceProvider*,
const RuntimeEffectDictionary*,
const UniqueKey&,
const GraphicsPipelineDesc&,
const RenderPassDesc&,
SkEnumBitMask<PipelineCreationFlags>,
uint32_t compilationID);
// The created program info can be provided to MakeLoadMSAAPipeline for reuse with different
// render pass descriptions. Returns null on failure.
static std::unique_ptr<VulkanProgramInfo> CreateLoadMSAAProgram(const VulkanSharedContext*);
static sk_sp<VulkanGraphicsPipeline> MakeLoadMSAAPipeline(
const VulkanSharedContext*,
VulkanResourceProvider*,
const VulkanProgramInfo& loadMSAAProgram,
const RenderPassDesc&);
~VulkanGraphicsPipeline() override {}
VkPipelineLayout layout() const {
SkASSERT(fPipelineLayout != VK_NULL_HANDLE);
return fPipelineLayout;
}
VkPipeline pipeline() const {
SkASSERT(fPipeline != VK_NULL_HANDLE);
return fPipeline;
}
private:
VulkanGraphicsPipeline(const VulkanSharedContext* sharedContext,
const PipelineInfo& pipelineInfo,
VkPipelineLayout,
VkPipeline,
bool ownsPipelineLayout,
skia_private::TArray<sk_sp<VulkanSampler>>&& immutableSamplers);
void freeGpuData() override;
// The fragment shader can be null if no shading is performed by the pipeline.
// This function does not cleanup any of the VulkanProgramInfo's objects on success or failure.
static VkPipeline MakePipeline(const VulkanSharedContext*,
VulkanResourceProvider*,
const VulkanProgramInfo&,
int subpassIndex,
PrimitiveType,
VkVertexInputRate appendInputRate,
SkSpan<const Attribute> staticAttrs,
SkSpan<const Attribute> appendAttrs,
const DepthStencilSettings&,
const BlendInfo&,
const RenderPassDesc&);
VkPipelineLayout fPipelineLayout = VK_NULL_HANDLE;
VkPipeline fPipeline = VK_NULL_HANDLE;
bool fOwnsPipelineLayout = true;
// Hold a ref to immutable samplers used such that their lifetime is properly managed.
const skia_private::TArray<sk_sp<VulkanSampler>> fImmutableSamplers;
};
} // namespace skgpu::graphite
#endif // skgpu_graphite_MtlGraphicsPipeline_DEFINED