blob: b43500bc8bf6a22adc223962836292e8e210c546 [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/SkBlockAllocator.h"
#include "src/base/SkTBlockList.h"
#include "src/gpu/graphite/CommandTypes.h"
#include "src/gpu/graphite/ResourceTypes.h"
#include <array>
#include <cstdint>
#include <type_traits>
#include <utility>
namespace skgpu::graphite {
enum class BarrierType : uint8_t;
enum class PrimitiveType : uint8_t;
enum class UniformSlot;
class TextureProxy;
namespace DrawPassCommands {
struct AddBarrier;
struct BindAppendDataBuffer;
struct BindGraphicsPipeline;
struct BindIndexBuffer;
struct BindIndirectBuffer;
struct BindStaticDataBuffer;
struct BindTexturesAndSamplers;
struct BindUniformBuffer;
struct Draw;
struct DrawIndexed;
struct DrawIndexedIndirect;
struct DrawIndexedInstanced;
struct DrawIndirect;
struct DrawInstanced;
struct SetBlendConstants;
struct SetScissor;
// 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(BindStaticDataBuffer) \
M(BindAppendDataBuffer) \
M(BindIndirectBuffer) \
M(BindIndexBuffer) \
M(BindTexturesAndSamplers) \
M(SetScissor) \
M(Draw) \
M(DrawIndexed) \
M(DrawInstanced) \
M(DrawIndexedInstanced) \
M(DrawIndirect) \
M(DrawIndexedIndirect) \
M(AddBarrier)
// 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,
std::array<float, 4> fBlendConstants);
COMMAND(BindUniformBuffer,
BindBufferInfo fInfo;
UniformSlot fSlot);
COMMAND(BindStaticDataBuffer,
BindBufferInfo fStaticData);
COMMAND(BindAppendDataBuffer,
BindBufferInfo fAppendData)
COMMAND(BindIndexBuffer,
BindBufferInfo fIndices);
COMMAND(BindIndirectBuffer,
BindBufferInfo fIndirect);
COMMAND(BindTexturesAndSamplers,
int fNumTexSamplers;
PODArray<const TextureProxy*> fTextures;
PODArray<SamplerDesc> fSamplers);
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);
COMMAND(AddBarrier,
BarrierType 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>(blendConstants);
}
void bindUniformBuffer(BindBufferInfo info, UniformSlot slot) {
this->add<BindUniformBuffer>(info, slot);
}
// Caller must write 'numTexSamplers' textures and sampler descriptions into the two returned
// arrays. The texture proxies must have refs held for the lifetime of this command list.
std::pair<const TextureProxy**, SamplerDesc*>
bindDeferredTexturesAndSamplers(int numTexSamplers) {
const TextureProxy** textures = fAlloc.makeArrayDefault<const TextureProxy*>(numTexSamplers);
SamplerDesc* samplers = fAlloc.makeArrayDefault<SamplerDesc>(numTexSamplers);
this->add<BindTexturesAndSamplers>(numTexSamplers, textures, samplers);
return {textures, samplers};
}
void setScissor(SkIRect scissor) {
this->add<SetScissor>(Scissor(scissor));
}
void bindStaticDataBuffer(BindBufferInfo staticAttribs) {
this->add<BindStaticDataBuffer>(staticAttribs);
}
void bindAppendDataBuffer(BindBufferInfo appendAttribs) {
this->add<BindAppendDataBuffer>(appendAttribs);
}
void bindIndexBuffer(BindBufferInfo indices) {
this->add<BindIndexBuffer>(indices);
}
void bindIndirectBuffer(BindBufferInfo indirect) {
this->add<BindIndirectBuffer>(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);
}
void addBarrier(BarrierType type) {
this->add<AddBarrier>(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));
}
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