blob: 1701bc7ade565d47f4df4ca5b2a014ef24b2c86c [file] [log] [blame]
/*
* 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