/* * 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/CommandTypes.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 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 fBlendConstants); COMMAND(BindUniformBuffer, BindBufferInfo fInfo; UniformSlot fSlot); COMMAND(BindDrawBuffers, BindBufferInfo fVertices; BindBufferInfo fInstances; BindBufferInfo fIndices; BindBufferInfo fIndirect); COMMAND(BindTexturesAndSamplers, int fNumTexSamplers; PODArray fTextureIndices; PODArray fSamplerIndices); COMMAND(SetScissor, Scissor 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::value); SKGPU_DRAW_PASS_COMMAND_TYPES(ASSERT_TRIV_DES) #undef ASSERT_TRIV_DES #define ASSERT_TRIV_CPY(T) static_assert(std::is_trivially_copyable::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(pipelineIndex); } void setBlendConstants(std::array blendConstants) { this->add(this->copy(blendConstants.data(), 4)); } void bindUniformBuffer(BindBufferInfo info, UniformSlot slot) { this->add(info, slot); } // Caller must write 'numTexSamplers' texture and sampler indices into the two returned arrays. std::pair bindDeferredTexturesAndSamplers(int numTexSamplers) { int* textureIndices = fAlloc.makeArrayDefault(numTexSamplers); int* samplerIndices = fAlloc.makeArrayDefault(numTexSamplers); this->add(numTexSamplers, textureIndices, samplerIndices); return {textureIndices, samplerIndices}; } void setScissor(SkIRect scissor) { this->add(Scissor(scissor)); } void bindDrawBuffers(BindBufferInfo vertexAttribs, BindBufferInfo instanceAttribs, BindBufferInfo indices, BindBufferInfo indirect) { this->add(vertexAttribs, instanceAttribs, indices, indirect); } void draw(PrimitiveType type, unsigned int baseVertex, unsigned int vertexCount) { this->add(type, baseVertex, vertexCount); } void drawIndexed(PrimitiveType type, unsigned int baseIndex, unsigned int indexCount, unsigned int baseVertex) { this->add(type, baseIndex, indexCount, baseVertex); } void drawInstanced(PrimitiveType type, unsigned int baseVertex, unsigned int vertexCount, unsigned int baseInstance, unsigned int instanceCount) { this->add(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(type, baseIndex, indexCount, baseVertex, baseInstance, instanceCount); } void drawIndirect(PrimitiveType type) { this->add(type); } void drawIndexedIndirect(PrimitiveType type) { this->add(type); } using Command = std::pair; using Iter = SkTBlockList::CIter; Iter commands() const { return fCommands.items(); } private: template void add(Args&&... args) { T* cmd = fAlloc.make(T{std::forward(args)...}); fCommands.push_back(std::make_pair(T::kType, cmd)); } // This copy() is for arrays. // It will work with POD only arrays. template T* copy(const T src[], size_t count) { static_assert(std::is_trivially_copyable::value); T* dst = fAlloc.makeArrayDefault(count); memcpy(dst, src, count*sizeof(T)); return dst; } SkTBlockList 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