[graphite] Add uniform buffer support to command buffer
Bug: skia:12466 Change-Id: Ie4c1973427e96d84b77f28edb5a4d6f1d53ef8aa Reviewed-on: https://skia-review.googlesource.com/c/skia/+/463316 Commit-Queue: Jim Van Verth <jvanverth@google.com> Reviewed-by: Greg Daniel <egdaniel@google.com>
This commit is contained in:
parent
8ed23eb917
commit
c545aa5aa6
@ -42,6 +42,12 @@ void CommandBuffer::bindRenderPipeline(sk_sp<RenderPipeline> renderPipeline) {
|
||||
fHasWork = true;
|
||||
}
|
||||
|
||||
void CommandBuffer::bindUniformBuffer(sk_sp<Buffer> uniformBuffer, size_t offset) {
|
||||
this->onBindUniformBuffer(uniformBuffer.get(), offset);
|
||||
this->trackResource(std::move(uniformBuffer));
|
||||
fHasWork = true;
|
||||
}
|
||||
|
||||
static bool check_max_blit_width(int widthInPixels) {
|
||||
if (widthInPixels > 32767) {
|
||||
SkASSERT(false); // surfaces should not be this wide anyway
|
||||
|
@ -57,6 +57,8 @@ public:
|
||||
//---------------------------------------------------------------
|
||||
void bindRenderPipeline(sk_sp<RenderPipeline> renderPipeline);
|
||||
|
||||
void bindUniformBuffer(sk_sp<Buffer>, size_t bufferOffset);
|
||||
|
||||
void draw(PrimitiveType type, unsigned int vertexStart, unsigned int vertexCount) {
|
||||
this->onDraw(type, vertexStart, vertexCount);
|
||||
fHasWork = true;
|
||||
@ -84,6 +86,9 @@ private:
|
||||
virtual void onBeginRenderPass(const RenderPassDesc&) = 0;
|
||||
|
||||
virtual void onBindRenderPipeline(const RenderPipeline*) = 0;
|
||||
|
||||
virtual void onBindUniformBuffer(const Buffer*, size_t bufferOffset) = 0;
|
||||
|
||||
virtual void onDraw(PrimitiveType type, unsigned int vertexStart, unsigned int vertexCount) = 0;
|
||||
|
||||
virtual void onCopyTextureToBuffer(const Texture*,
|
||||
|
@ -28,20 +28,36 @@ public:
|
||||
return fKey.size() * sizeof(uint32_t);
|
||||
}
|
||||
|
||||
bool operator== (const RenderPipelineDesc& that) const {
|
||||
bool operator==(const RenderPipelineDesc& that) const {
|
||||
return this->fKey == that.fKey;
|
||||
}
|
||||
|
||||
bool operator!= (const RenderPipelineDesc& other) const {
|
||||
bool operator!=(const RenderPipelineDesc& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
// TODO: remove this once we have something real working
|
||||
void setTestingOnlyShaderIndex(int index) {
|
||||
fTestingOnlyShaderIndex = index;
|
||||
if (fKey.count() >= 1) {
|
||||
fKey[0] = index;
|
||||
} else {
|
||||
fKey.push_back(index);
|
||||
}
|
||||
}
|
||||
|
||||
int testingOnlyShaderIndex() const {
|
||||
return fTestingOnlyShaderIndex;
|
||||
}
|
||||
|
||||
private:
|
||||
// Estimate of max expected key size
|
||||
// TODO: flesh this out
|
||||
inline static constexpr int kPreAllocSize = 1;
|
||||
|
||||
SkSTArray<kPreAllocSize, uint32_t, true> fKey;
|
||||
|
||||
int fTestingOnlyShaderIndex;
|
||||
};
|
||||
|
||||
} // namespace skgpu
|
||||
|
@ -49,6 +49,8 @@ private:
|
||||
|
||||
void onBindRenderPipeline(const skgpu::RenderPipeline*) override;
|
||||
|
||||
void onBindUniformBuffer(const skgpu::Buffer*, size_t offset) override;
|
||||
|
||||
void onDraw(PrimitiveType type, unsigned int vertexStart, unsigned int vertexCount) override;
|
||||
|
||||
void onCopyTextureToBuffer(const skgpu::Texture*,
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
namespace skgpu::mtl {
|
||||
|
||||
static constexpr size_t kUniformBufferIndex = 0;
|
||||
|
||||
sk_sp<CommandBuffer> CommandBuffer::Make(const Gpu* gpu) {
|
||||
sk_cfp<id<MTLCommandBuffer>> cmdBuffer;
|
||||
id<MTLCommandQueue> queue = gpu->queue();
|
||||
@ -145,6 +147,14 @@ void CommandBuffer::onBindRenderPipeline(const skgpu::RenderPipeline* renderPipe
|
||||
fActiveRenderCommandEncoder->setRenderPipelineState(pipelineState);
|
||||
}
|
||||
|
||||
void CommandBuffer::onBindUniformBuffer(const skgpu::Buffer* uniformBuffer,
|
||||
size_t uniformOffset) {
|
||||
id<MTLBuffer> mtlBuffer = static_cast<const Buffer*>(uniformBuffer)->mtlBuffer();
|
||||
|
||||
fActiveRenderCommandEncoder->setVertexBuffer(mtlBuffer, uniformOffset, kUniformBufferIndex);
|
||||
fActiveRenderCommandEncoder->setFragmentBuffer(mtlBuffer, uniformOffset, kUniformBufferIndex);
|
||||
}
|
||||
|
||||
static MTLPrimitiveType graphite_to_mtl_primitive(PrimitiveType primitiveType) {
|
||||
const static MTLPrimitiveType mtlPrimitiveType[] {
|
||||
MTLPrimitiveTypeTriangle,
|
||||
|
@ -7,45 +7,83 @@
|
||||
|
||||
#include "experimental/graphite/src/mtl/MtlRenderPipeline.h"
|
||||
|
||||
#include "experimental/graphite/src/RenderPipelineDesc.h"
|
||||
#include "experimental/graphite/src/mtl/MtlGpu.h"
|
||||
#include "experimental/graphite/src/mtl/MtlUtils.h"
|
||||
#include "include/private/SkSLString.h"
|
||||
|
||||
namespace skgpu::mtl {
|
||||
|
||||
sk_sp<RenderPipeline> RenderPipeline::Make(const Gpu* gpu, const skgpu::RenderPipelineDesc&) {
|
||||
static const char* kTestingOnlyShaders[] = {
|
||||
// clear viewport to blue
|
||||
"#include <metal_stdlib>\n"
|
||||
"#include <simd/simd.h>\n"
|
||||
"using namespace metal;\n"
|
||||
"\n"
|
||||
"typedef struct {\n"
|
||||
" float4 position [[position]];\n"
|
||||
"} VertexOutput;\n"
|
||||
"\n"
|
||||
"vertex VertexOutput vertexMain(uint vertexID [[vertex_id]]) {\n"
|
||||
" VertexOutput out;\n"
|
||||
" float2 position = float2(float(vertexID >> 1), float(vertexID & 1));\n"
|
||||
" out.position.xy = position * 2 - 1;\n"
|
||||
" out.position.zw = float2(0.0, 1.0);\n"
|
||||
" return out;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"fragment float4 fragmentMain(VertexOutput in [[stage_in]]) {\n"
|
||||
" return float4(0.0, 0.0, 1.0, 1.0);\n"
|
||||
"}",
|
||||
|
||||
// clear subarea to given color, using uniform buffer
|
||||
"#include <metal_stdlib>\n"
|
||||
"#include <simd/simd.h>\n"
|
||||
"using namespace metal;\n"
|
||||
"\n"
|
||||
"typedef struct {\n"
|
||||
" float4 position [[position]];\n"
|
||||
"} VertexOutput;\n"
|
||||
"\n"
|
||||
"typedef struct {\n"
|
||||
" float4 uPosXform;\n"
|
||||
" float4 uColor;\n"
|
||||
"} UniformData;\n"
|
||||
"\n"
|
||||
"vertex VertexOutput vertexMain(constant UniformData& uniforms [[buffer(0)]],\n"
|
||||
" uint vertexID [[vertex_id]]) {\n"
|
||||
" VertexOutput out;\n"
|
||||
" float2 position = float2(float(vertexID >> 1), float(vertexID & 1));\n"
|
||||
" out.position.xy = position * uniforms.uPosXform.xy + uniforms.uPosXform.zw;\n"
|
||||
" out.position.zw = float2(0.0, 1.0);\n"
|
||||
" return out;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"fragment float4 fragmentMain(constant UniformData& uniforms [[buffer(0)]],\n"
|
||||
" VertexOutput in [[stage_in]]) {\n"
|
||||
" return uniforms.uColor;\n"
|
||||
"}",
|
||||
};
|
||||
|
||||
static constexpr NSString* kTestingOnlyShaderLabels[] = {
|
||||
@"Clear viewport to blue",
|
||||
@"Clear rect with uniforms"
|
||||
};
|
||||
|
||||
sk_sp<RenderPipeline> RenderPipeline::Make(const Gpu* gpu, const skgpu::RenderPipelineDesc& desc) {
|
||||
sk_cfp<MTLRenderPipelineDescriptor*> psoDescriptor([[MTLRenderPipelineDescriptor alloc] init]);
|
||||
|
||||
// Temp pipeline for now that just fills the viewport with blue
|
||||
int shaderIndex = desc.testingOnlyShaderIndex();
|
||||
SkSL::String shaderText;
|
||||
shaderText.append(
|
||||
"#include <metal_stdlib>\n"
|
||||
"#include <simd/simd.h>\n"
|
||||
"using namespace metal;\n"
|
||||
"\n"
|
||||
"typedef struct {\n"
|
||||
" float4 position [[position]];\n"
|
||||
"} VertexOutput;\n"
|
||||
"\n"
|
||||
"vertex VertexOutput vertexMain(uint vertexID [[vertex_id]]) {\n"
|
||||
" VertexOutput out;\n"
|
||||
" float2 position = float2(float(vertexID >> 1), float(vertexID & 1));\n"
|
||||
" out.position.xy = position * 2 - 1;\n"
|
||||
" out.position.zw = float2(0.0, 1.0);\n"
|
||||
" return out;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"fragment float4 fragmentMain(VertexOutput in [[stage_in]]) {\n"
|
||||
" return float4(0.0, 0.0, 1.0, 1.0);\n"
|
||||
"}"
|
||||
);
|
||||
shaderText.append(kTestingOnlyShaders[shaderIndex]);
|
||||
|
||||
auto metallib = CompileShaderLibrary(gpu, shaderText);
|
||||
if (!metallib) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
(*psoDescriptor).label = @"testPipeline";
|
||||
(*psoDescriptor).label = kTestingOnlyShaderLabels[shaderIndex];
|
||||
|
||||
(*psoDescriptor).vertexFunction =
|
||||
[*metallib newFunctionWithName: @"vertexMain"];
|
||||
|
@ -29,6 +29,9 @@ using namespace skgpu;
|
||||
* This is to test the various pieces of the CommandBuffer interface.
|
||||
*/
|
||||
DEF_GRAPHITE_TEST_FOR_CONTEXTS(CommandBufferTest, reporter, context) {
|
||||
constexpr int kTextureWidth = 1024;
|
||||
constexpr int kTextureHeight = 768;
|
||||
|
||||
auto gpu = context->priv().gpu();
|
||||
REPORTER_ASSERT(reporter, gpu);
|
||||
|
||||
@ -37,7 +40,7 @@ DEF_GRAPHITE_TEST_FOR_CONTEXTS(CommandBufferTest, reporter, context) {
|
||||
#endif
|
||||
auto commandBuffer = gpu->resourceProvider()->createCommandBuffer();
|
||||
|
||||
SkISize textureSize = { 1024, 768 };
|
||||
SkISize textureSize = { kTextureWidth, kTextureHeight };
|
||||
#ifdef SK_METAL
|
||||
skgpu::mtl::TextureInfo mtlTextureInfo = {
|
||||
1,
|
||||
@ -59,31 +62,52 @@ DEF_GRAPHITE_TEST_FOR_CONTEXTS(CommandBufferTest, reporter, context) {
|
||||
renderPassDesc.fColorAttachment.fTexture = texture;
|
||||
renderPassDesc.fColorAttachment.fLoadOp = LoadOp::kClear;
|
||||
renderPassDesc.fColorAttachment.fStoreOp = StoreOp::kStore;
|
||||
renderPassDesc.fClearColor = { 1, 0, 0, 1 };
|
||||
renderPassDesc.fClearColor = { 1, 0, 0, 1 }; // red
|
||||
|
||||
commandBuffer->beginRenderPass(renderPassDesc);
|
||||
|
||||
RenderPipelineDesc pipelineDesc;
|
||||
pipelineDesc.setTestingOnlyShaderIndex(1);
|
||||
auto renderPipeline = gpu->resourceProvider()->findOrCreateRenderPipeline(pipelineDesc);
|
||||
commandBuffer->bindRenderPipeline(std::move(renderPipeline));
|
||||
struct UniformData {
|
||||
float fPosXform[4];
|
||||
float fColor[4];
|
||||
};
|
||||
sk_sp<Buffer> uniformBuffer = gpu->resourceProvider()->findOrCreateBuffer(
|
||||
sizeof(UniformData), BufferType::kUniform, PrioritizeGpuReads::kNo);
|
||||
UniformData* uniforms = (UniformData*)uniformBuffer->map();
|
||||
uniforms->fPosXform[0] = 2;
|
||||
uniforms->fPosXform[1] = 2;
|
||||
uniforms->fPosXform[2] = -1;
|
||||
uniforms->fPosXform[3] = -1;
|
||||
uniforms->fColor[0] = 1;
|
||||
uniforms->fColor[1] = 1;
|
||||
uniforms->fColor[2] = 0;
|
||||
uniforms->fColor[3] = 1;
|
||||
uniformBuffer->unmap();
|
||||
commandBuffer->bindUniformBuffer(uniformBuffer, 0);
|
||||
commandBuffer->draw(PrimitiveType::kTriangleStrip, 0, 4);
|
||||
|
||||
commandBuffer->endRenderPass();
|
||||
|
||||
sk_sp<Buffer> buffer = gpu->resourceProvider()->findOrCreateBuffer(1024*768*4,
|
||||
BufferType::kXferGpuToCpu,
|
||||
PrioritizeGpuReads::kNo);
|
||||
REPORTER_ASSERT(reporter, buffer);
|
||||
SkIRect srcRect = { 0, 0, 1024, 768 };
|
||||
size_t rowBytes = 1024*4;
|
||||
commandBuffer->copyTextureToBuffer(texture, srcRect, buffer, 0, rowBytes);
|
||||
// TODO: add 4-byte transfer buffer alignment for Mac to Caps
|
||||
// add bpp to Caps
|
||||
size_t rowBytes = 4*kTextureWidth;
|
||||
size_t bufferSize = rowBytes*kTextureHeight;
|
||||
sk_sp<Buffer> copyBuffer = gpu->resourceProvider()->findOrCreateBuffer(
|
||||
bufferSize, BufferType::kXferGpuToCpu, PrioritizeGpuReads::kNo);
|
||||
REPORTER_ASSERT(reporter, copyBuffer);
|
||||
SkIRect srcRect = { 0, 0, kTextureWidth, kTextureHeight };
|
||||
commandBuffer->copyTextureToBuffer(texture, srcRect, copyBuffer, 0, rowBytes);
|
||||
|
||||
bool result = gpu->submit(commandBuffer);
|
||||
REPORTER_ASSERT(reporter, result);
|
||||
|
||||
gpu->checkForFinishedWork(skgpu::SyncToCpu::kYes);
|
||||
uint32_t* pixels = (uint32_t*)(buffer->map());
|
||||
REPORTER_ASSERT(reporter, pixels[0] == 0xffff0000);
|
||||
uint32_t* pixels = (uint32_t*)(copyBuffer->map());
|
||||
REPORTER_ASSERT(reporter, pixels[0] == 0xff00ffff);
|
||||
copyBuffer->unmap();
|
||||
|
||||
#if GRAPHITE_TEST_UTILS && CAPTURE_COMMANDBUFFER
|
||||
gpu->testingOnly_endCapture();
|
||||
|
Loading…
Reference in New Issue
Block a user