| /* |
| * Copyright 2022 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_DrawPassCommands_DEFINED |
| #define skgpu_graphite_DrawPassCommands_DEFINED |
| |
| #include "include/core/SkRect.h" |
| #include "src/base/SkArenaAlloc.h" |
| #include "src/base/SkTBlockList.h" |
| #include "src/gpu/graphite/DrawTypes.h" |
| |
| namespace skgpu::graphite { |
| |
| namespace DrawPassCommands { |
| |
| // A list of all the commands types used by a DrawPass. |
| // Each of these is reified into a struct below. |
| // |
| // The design of this systems is based on SkRecords. |
| |
| // (We're using the macro-of-macro trick here to do several different things with the same list.) |
| // |
| // We leave this SKGPU_DRAW_COMMAND_TYPES macro defined for use by code that wants to operate on |
| // DrawPassCommands types polymorphically. |
| #define SKGPU_DRAW_PASS_COMMAND_TYPES(M) \ |
| M(BindGraphicsPipeline) \ |
| M(SetBlendConstants) \ |
| M(BindUniformBuffer) \ |
| M(BindDrawBuffers) \ |
| M(BindTexturesAndSamplers) \ |
| M(SetScissor) \ |
| M(Draw) \ |
| M(DrawIndexed) \ |
| M(DrawInstanced) \ |
| M(DrawIndexedInstanced) \ |
| M(DrawIndirect) \ |
| M(DrawIndexedIndirect) |
| |
| // Defines DrawPassCommands::Type, an enum of all draw command types. |
| #define ENUM(T) k##T, |
| enum class Type { SKGPU_DRAW_PASS_COMMAND_TYPES(ENUM) }; |
| #undef ENUM |
| |
| #define ACT_AS_PTR(ptr) \ |
| operator T*() const { return ptr; } \ |
| T* operator->() const { return ptr; } |
| |
| // PODArray doesn't own the pointer's memory, and we assume the data is POD. |
| template <typename T> |
| class PODArray { |
| public: |
| PODArray() {} |
| PODArray(T* ptr) : fPtr(ptr) {} |
| // Default copy and assign. |
| |
| ACT_AS_PTR(fPtr) |
| private: |
| T* fPtr; |
| }; |
| |
| #undef ACT_AS_PTR |
| |
| // A macro to make it a little easier to define a struct that can be stored in DrawPass. |
| #define COMMAND(T, ...) \ |
| struct T { \ |
| static constexpr Type kType = Type::k##T; \ |
| __VA_ARGS__; \ |
| }; |
| |
| COMMAND(BindGraphicsPipeline, |
| uint32_t fPipelineIndex); |
| COMMAND(SetBlendConstants, |
| PODArray<float> fBlendConstants); |
| COMMAND(BindUniformBuffer, |
| BindUniformBufferInfo fInfo; |
| UniformSlot fSlot); |
| COMMAND(BindDrawBuffers, |
| BindBufferInfo fVertices; |
| BindBufferInfo fInstances; |
| BindBufferInfo fIndices; |
| BindBufferInfo fIndirect); |
| COMMAND(BindTexturesAndSamplers, |
| int fNumTexSamplers; |
| PODArray<int> fTextureIndices; |
| PODArray<int> fSamplerIndices); |
| COMMAND(SetScissor, |
| SkIRect fScissor); |
| COMMAND(Draw, |
| PrimitiveType fType; |
| uint32_t fBaseVertex; |
| uint32_t fVertexCount); |
| COMMAND(DrawIndexed, |
| PrimitiveType fType; |
| uint32_t fBaseIndex; |
| uint32_t fIndexCount; |
| uint32_t fBaseVertex); |
| COMMAND(DrawInstanced, |
| PrimitiveType fType; |
| uint32_t fBaseVertex; |
| uint32_t fVertexCount; |
| uint32_t fBaseInstance; |
| uint32_t fInstanceCount); |
| COMMAND(DrawIndexedInstanced, |
| PrimitiveType fType; |
| uint32_t fBaseIndex; |
| uint32_t fIndexCount; |
| uint32_t fBaseVertex; |
| uint32_t fBaseInstance; |
| uint32_t fInstanceCount); |
| COMMAND(DrawIndirect, |
| PrimitiveType fType); |
| COMMAND(DrawIndexedIndirect, |
| PrimitiveType fType); |
| |
| #undef COMMAND |
| |
| #define ASSERT_TRIV_DES(T) static_assert(std::is_trivially_destructible<T>::value); |
| SKGPU_DRAW_PASS_COMMAND_TYPES(ASSERT_TRIV_DES) |
| #undef ASSERT_TRIV_DES |
| #define ASSERT_TRIV_CPY(T) static_assert(std::is_trivially_copyable<T>::value); |
| SKGPU_DRAW_PASS_COMMAND_TYPES(ASSERT_TRIV_CPY) |
| #undef ASSERT_TRIV_CPY |
| |
| class List { |
| public: |
| List() = default; |
| ~List() = default; |
| |
| int count() const { return fCommands.count(); } |
| |
| void bindGraphicsPipeline(uint32_t pipelineIndex) { |
| this->add<BindGraphicsPipeline>(pipelineIndex); |
| } |
| |
| void setBlendConstants(std::array<float, 4> blendConstants) { |
| this->add<SetBlendConstants>(this->copy(blendConstants.data(), 4)); |
| } |
| |
| void bindUniformBuffer(BindUniformBufferInfo info, UniformSlot slot) { |
| this->add<BindUniformBuffer>(info, slot); |
| } |
| |
| // Caller must write 'numTexSamplers' texture and sampler indices into the two returned arrays. |
| std::pair<int*, int*> |
| bindDeferredTexturesAndSamplers(int numTexSamplers) { |
| int* textureIndices = fAlloc.makeArrayDefault<int>(numTexSamplers); |
| int* samplerIndices = fAlloc.makeArrayDefault<int>(numTexSamplers); |
| this->add<BindTexturesAndSamplers>(numTexSamplers, textureIndices, samplerIndices); |
| return {textureIndices, samplerIndices}; |
| } |
| |
| void setScissor(SkIRect scissor) { |
| this->add<SetScissor>(scissor); |
| } |
| |
| void bindDrawBuffers(BindBufferInfo vertexAttribs, |
| BindBufferInfo instanceAttribs, |
| BindBufferInfo indices, |
| BindBufferInfo indirect) { |
| this->add<BindDrawBuffers>(vertexAttribs, instanceAttribs, indices, indirect); |
| } |
| |
| void draw(PrimitiveType type, unsigned int baseVertex, unsigned int vertexCount) { |
| this->add<Draw>(type, baseVertex, vertexCount); |
| } |
| |
| void drawIndexed(PrimitiveType type, unsigned int baseIndex, |
| unsigned int indexCount, unsigned int baseVertex) { |
| this->add<DrawIndexed>(type, baseIndex, indexCount, baseVertex); |
| } |
| |
| void drawInstanced(PrimitiveType type, |
| unsigned int baseVertex, unsigned int vertexCount, |
| unsigned int baseInstance, unsigned int instanceCount) { |
| this->add<DrawInstanced>(type, baseVertex, vertexCount, baseInstance, instanceCount); |
| } |
| |
| void drawIndexedInstanced(PrimitiveType type, |
| unsigned int baseIndex, unsigned int indexCount, |
| unsigned int baseVertex, unsigned int baseInstance, |
| unsigned int instanceCount) { |
| this->add<DrawIndexedInstanced>(type, |
| baseIndex, |
| indexCount, |
| baseVertex, |
| baseInstance, |
| instanceCount); |
| } |
| |
| void drawIndirect(PrimitiveType type) { |
| this->add<DrawIndirect>(type); |
| } |
| |
| void drawIndexedIndirect(PrimitiveType type) { |
| this->add<DrawIndexedIndirect>(type); |
| } |
| |
| using Command = std::pair<Type, void*>; |
| using Iter = SkTBlockList<Command, 16>::CIter; |
| Iter commands() const { return fCommands.items(); } |
| |
| private: |
| template <typename T, typename... Args> |
| void add(Args&&... args) { |
| T* cmd = fAlloc.make<T>(T{std::forward<Args>(args)...}); |
| fCommands.push_back(std::make_pair(T::kType, cmd)); |
| } |
| |
| // This copy() is for arrays. |
| // It will work with POD only arrays. |
| template <typename T> |
| T* copy(const T src[], size_t count) { |
| static_assert(std::is_trivially_copyable<T>::value); |
| T* dst = fAlloc.makeArrayDefault<T>(count); |
| memcpy(dst, src, count*sizeof(T)); |
| return dst; |
| } |
| |
| SkTBlockList<Command, 16> fCommands{SkBlockAllocator::GrowthPolicy::kFibonacci}; |
| |
| // fAlloc needs to be a data structure which can append variable length data in contiguous |
| // chunks, returning a stable handle to that data for later retrieval. |
| SkArenaAlloc fAlloc{256}; |
| }; |
| |
| } // namespace DrawPassCommands |
| |
| } // namespace skgpu::graphite |
| |
| #endif // skgpu_graphite_DrawPassCommands_DEFINED |