mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-12-17 00:47:13 +00:00
Introduce render passes
* First API design (many features missing, including input attachments) * Metal implementation (no OpenGL yet) * Render-to-texture demo (a little broken until we have depth buffers) * Update examples to use render passes
This commit is contained in:
committed by
Kai Ninomiya
parent
ca309db58a
commit
68df8b0a3a
@@ -27,9 +27,11 @@
|
||||
#include "common/Device.h"
|
||||
#include "common/CommandBuffer.h"
|
||||
#include "common/InputState.h"
|
||||
#include "common/Framebuffer.h"
|
||||
#include "common/Pipeline.h"
|
||||
#include "common/PipelineLayout.h"
|
||||
#include "common/Queue.h"
|
||||
#include "common/RenderPass.h"
|
||||
#include "common/Sampler.h"
|
||||
#include "common/ShaderModule.h"
|
||||
#include "common/Texture.h"
|
||||
@@ -52,9 +54,11 @@ namespace metal {
|
||||
class BufferView;
|
||||
class CommandBuffer;
|
||||
class InputState;
|
||||
class Framebuffer;
|
||||
class Pipeline;
|
||||
class PipelineLayout;
|
||||
class Queue;
|
||||
class RenderPass;
|
||||
class Sampler;
|
||||
class ShaderModule;
|
||||
class Texture;
|
||||
@@ -67,9 +71,11 @@ namespace metal {
|
||||
using BufferViewType = BufferView;
|
||||
using CommandBufferType = CommandBuffer;
|
||||
using InputStateType = InputState;
|
||||
using FramebufferType = Framebuffer;
|
||||
using PipelineType = Pipeline;
|
||||
using PipelineLayoutType = PipelineLayout;
|
||||
using QueueType = Queue;
|
||||
using RenderPassType = RenderPass;
|
||||
using SamplerType = Sampler;
|
||||
using ShaderModuleType = ShaderModule;
|
||||
using TextureType = Texture;
|
||||
@@ -92,9 +98,11 @@ namespace metal {
|
||||
BufferViewBase* CreateBufferView(BufferViewBuilder* builder) override;
|
||||
CommandBufferBase* CreateCommandBuffer(CommandBufferBuilder* builder) override;
|
||||
InputStateBase* CreateInputState(InputStateBuilder* builder) override;
|
||||
FramebufferBase* CreateFramebuffer(FramebufferBuilder* builder) override;
|
||||
PipelineBase* CreatePipeline(PipelineBuilder* builder) override;
|
||||
PipelineLayoutBase* CreatePipelineLayout(PipelineLayoutBuilder* builder) override;
|
||||
QueueBase* CreateQueue(QueueBuilder* builder) override;
|
||||
RenderPassBase* CreateRenderPass(RenderPassBuilder* builder) override;
|
||||
SamplerBase* CreateSampler(SamplerBuilder* builder) override;
|
||||
ShaderModuleBase* CreateShaderModule(ShaderModuleBuilder* builder) override;
|
||||
TextureBase* CreateTexture(TextureBuilder* builder) override;
|
||||
@@ -184,6 +192,15 @@ namespace metal {
|
||||
MTLVertexDescriptor* mtlVertexDescriptor = nil;
|
||||
};
|
||||
|
||||
class Framebuffer : public FramebufferBase {
|
||||
public:
|
||||
Framebuffer(Device* device, FramebufferBuilder* builder);
|
||||
~Framebuffer();
|
||||
|
||||
private:
|
||||
Device* device;
|
||||
};
|
||||
|
||||
class Pipeline : public PipelineBase {
|
||||
public:
|
||||
Pipeline(Device* device, PipelineBuilder* builder);
|
||||
@@ -230,6 +247,15 @@ namespace metal {
|
||||
id<MTLCommandQueue> commandQueue = nil;
|
||||
};
|
||||
|
||||
class RenderPass : public RenderPassBase {
|
||||
public:
|
||||
RenderPass(Device* device, RenderPassBuilder* builder);
|
||||
~RenderPass();
|
||||
|
||||
private:
|
||||
Device* device;
|
||||
};
|
||||
|
||||
class Sampler : public SamplerBase {
|
||||
public:
|
||||
Sampler(Device* device, SamplerBuilder* builder);
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// TODO(kainino@chromium.org): split this backend into many files
|
||||
|
||||
#include "MetalBackend.h"
|
||||
|
||||
#include <spirv-cross/spirv_msl.hpp>
|
||||
@@ -81,6 +83,9 @@ namespace metal {
|
||||
InputStateBase* Device::CreateInputState(InputStateBuilder* builder) {
|
||||
return new InputState(this, builder);
|
||||
}
|
||||
FramebufferBase* Device::CreateFramebuffer(FramebufferBuilder* builder) {
|
||||
return new Framebuffer(this, builder);
|
||||
}
|
||||
PipelineBase* Device::CreatePipeline(PipelineBuilder* builder) {
|
||||
return new Pipeline(this, builder);
|
||||
}
|
||||
@@ -90,6 +95,9 @@ namespace metal {
|
||||
QueueBase* Device::CreateQueue(QueueBuilder* builder) {
|
||||
return new Queue(this, builder);
|
||||
}
|
||||
RenderPassBase* Device::CreateRenderPass(RenderPassBuilder* builder) {
|
||||
return new RenderPass(this, builder);
|
||||
}
|
||||
SamplerBase* Device::CreateSampler(SamplerBuilder* builder) {
|
||||
return new Sampler(this, builder);
|
||||
}
|
||||
@@ -248,7 +256,10 @@ namespace metal {
|
||||
id<MTLComputeCommandEncoder> compute = nil;
|
||||
id<MTLRenderCommandEncoder> render = nil;
|
||||
|
||||
BeginRenderPassCmd* currentRenderPass = nullptr;
|
||||
|
||||
void FinishEncoders() {
|
||||
ASSERT(render == nil);
|
||||
if (blit != nil) {
|
||||
[blit endEncoding];
|
||||
blit = nil;
|
||||
@@ -257,10 +268,6 @@ namespace metal {
|
||||
[compute endEncoding];
|
||||
compute = nil;
|
||||
}
|
||||
if (render != nil) {
|
||||
[render endEncoding];
|
||||
render = nil;
|
||||
}
|
||||
}
|
||||
|
||||
void EnsureBlit(id<MTLCommandBuffer> commandBuffer) {
|
||||
@@ -276,22 +283,49 @@ namespace metal {
|
||||
// TODO(cwallez@chromium.org): does any state need to be reset?
|
||||
}
|
||||
}
|
||||
void EnsureRender(id<MTLCommandBuffer> commandBuffer) {
|
||||
if (render == nil) {
|
||||
FinishEncoders();
|
||||
void BeginSubpass(id<MTLCommandBuffer> commandBuffer, uint32_t subpass) {
|
||||
ASSERT(currentRenderPass);
|
||||
if (render != nil) {
|
||||
[render endEncoding];
|
||||
render = nil;
|
||||
}
|
||||
|
||||
// TODO(cwallez@chromium.org): this should be created from a renderpass subpass
|
||||
MTLRenderPassDescriptor* descriptor = [MTLRenderPassDescriptor renderPassDescriptor];
|
||||
descriptor.colorAttachments[0].texture = device->GetCurrentTexture();
|
||||
descriptor.colorAttachments[0].loadAction = MTLLoadActionLoad;
|
||||
descriptor.colorAttachments[0].storeAction = MTLStoreActionStore;
|
||||
const auto& info = currentRenderPass->renderPass->GetSubpassInfo(subpass);
|
||||
auto& framebuffer = currentRenderPass->framebuffer;
|
||||
|
||||
MTLRenderPassDescriptor* descriptor = [MTLRenderPassDescriptor renderPassDescriptor];
|
||||
bool usingBackbuffer = false; // HACK(kainino@chromium.org): workaround for not having depth attachments
|
||||
for (uint32_t index = 0; index < info.colorAttachments.size(); ++index) {
|
||||
uint32_t attachment = info.colorAttachments[index];
|
||||
|
||||
// TODO(kainino@chromium.org): currently a 'null' texture view
|
||||
// falls back to the 'back buffer' but this should go away
|
||||
// when we have WSI.
|
||||
id<MTLTexture> texture = nil;
|
||||
if (auto textureView = framebuffer->GetTextureView(attachment)) {
|
||||
texture = ToBackend(textureView->GetTexture())->GetMTLTexture();
|
||||
} else {
|
||||
texture = device->GetCurrentTexture();
|
||||
usingBackbuffer = true;
|
||||
}
|
||||
descriptor.colorAttachments[index].texture = texture;
|
||||
descriptor.colorAttachments[index].loadAction = MTLLoadActionLoad;
|
||||
descriptor.colorAttachments[index].storeAction = MTLStoreActionStore;
|
||||
}
|
||||
// TODO(kainino@chromium.org): load depth attachment from subpass
|
||||
if (usingBackbuffer) {
|
||||
descriptor.depthAttachment.texture = device->GetCurrentDepthTexture();
|
||||
descriptor.depthAttachment.loadAction = MTLLoadActionLoad;
|
||||
descriptor.depthAttachment.storeAction = MTLStoreActionStore;
|
||||
|
||||
render = [commandBuffer renderCommandEncoderWithDescriptor:descriptor];
|
||||
// TODO(cwallez@chromium.org): does any state need to be reset?
|
||||
}
|
||||
|
||||
render = [commandBuffer renderCommandEncoderWithDescriptor:descriptor];
|
||||
// TODO(cwallez@chromium.org): does any state need to be reset?
|
||||
}
|
||||
void EndRenderPass() {
|
||||
ASSERT(render != nil);
|
||||
[render endEncoding];
|
||||
render = nil;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -307,15 +341,34 @@ namespace metal {
|
||||
CurrentEncoders encoders;
|
||||
encoders.device = device;
|
||||
|
||||
uint32_t currentSubpass = 0;
|
||||
id<MTLRenderCommandEncoder> renderEncoder = nil;
|
||||
|
||||
while (commands.NextCommandId(&type)) {
|
||||
switch (type) {
|
||||
case Command::AdvanceSubpass:
|
||||
{
|
||||
commands.NextCommand<AdvanceSubpassCmd>();
|
||||
currentSubpass += 1;
|
||||
encoders.BeginSubpass(commandBuffer, currentSubpass);
|
||||
}
|
||||
break;
|
||||
|
||||
case Command::BeginRenderPass:
|
||||
{
|
||||
encoders.currentRenderPass = commands.NextCommand<BeginRenderPassCmd>();
|
||||
encoders.FinishEncoders();
|
||||
currentSubpass = 0;
|
||||
encoders.BeginSubpass(commandBuffer, currentSubpass);
|
||||
}
|
||||
break;
|
||||
|
||||
case Command::CopyBufferToTexture:
|
||||
{
|
||||
CopyBufferToTextureCmd* copy = commands.NextCommand<CopyBufferToTextureCmd>();
|
||||
Buffer* buffer = ToBackend(copy->buffer.Get());
|
||||
Texture* texture = ToBackend(copy->texture.Get());
|
||||
|
||||
// TODO(kainino@chromium.org): this has to be in a Blit encoder, not a Render encoder, so ordering is lost here
|
||||
unsigned rowSize = copy->width * TextureFormatPixelSize(texture->GetFormat());
|
||||
MTLOrigin origin;
|
||||
origin.x = copy->x;
|
||||
@@ -356,7 +409,7 @@ namespace metal {
|
||||
{
|
||||
DrawArraysCmd* draw = commands.NextCommand<DrawArraysCmd>();
|
||||
|
||||
encoders.EnsureRender(commandBuffer);
|
||||
ASSERT(encoders.render);
|
||||
[encoders.render
|
||||
drawPrimitives:MTLPrimitiveTypeTriangle
|
||||
vertexStart:draw->firstVertex
|
||||
@@ -370,7 +423,7 @@ namespace metal {
|
||||
{
|
||||
DrawElementsCmd* draw = commands.NextCommand<DrawElementsCmd>();
|
||||
|
||||
encoders.EnsureRender(commandBuffer);
|
||||
ASSERT(encoders.render);
|
||||
[encoders.render
|
||||
drawIndexedPrimitives:MTLPrimitiveTypeTriangle
|
||||
indexCount:draw->indexCount
|
||||
@@ -383,6 +436,13 @@ namespace metal {
|
||||
}
|
||||
break;
|
||||
|
||||
case Command::EndRenderPass:
|
||||
{
|
||||
commands.NextCommand<EndRenderPassCmd>();
|
||||
encoders.EndRenderPass();
|
||||
}
|
||||
break;
|
||||
|
||||
case Command::SetPipeline:
|
||||
{
|
||||
SetPipelineCmd* cmd = commands.NextCommand<SetPipelineCmd>();
|
||||
@@ -392,7 +452,7 @@ namespace metal {
|
||||
encoders.EnsureCompute(commandBuffer);
|
||||
lastPipeline->Encode(encoders.compute);
|
||||
} else {
|
||||
encoders.EnsureRender(commandBuffer);
|
||||
ASSERT(encoders.render);
|
||||
lastPipeline->Encode(encoders.render);
|
||||
}
|
||||
}
|
||||
@@ -420,7 +480,7 @@ namespace metal {
|
||||
if (lastPipeline->IsCompute()) {
|
||||
encoders.EnsureCompute(commandBuffer);
|
||||
} else {
|
||||
encoders.EnsureRender(commandBuffer);
|
||||
ASSERT(encoders.render);
|
||||
}
|
||||
|
||||
// TODO(kainino@chromium.org): Maintain buffers and offsets arrays in BindGroup so that we
|
||||
@@ -558,7 +618,7 @@ namespace metal {
|
||||
mtlOffsets[i] = offsets[i];
|
||||
}
|
||||
|
||||
encoders.EnsureRender(commandBuffer);
|
||||
ASSERT(encoders.render);
|
||||
[encoders.render
|
||||
setVertexBuffers:mtlBuffers.data()
|
||||
offsets:mtlOffsets.data()
|
||||
@@ -662,6 +722,15 @@ namespace metal {
|
||||
return mtlVertexDescriptor;
|
||||
}
|
||||
|
||||
// Framebuffer
|
||||
|
||||
Framebuffer::Framebuffer(Device* device, FramebufferBuilder* builder)
|
||||
: FramebufferBase(builder), device(device) {
|
||||
}
|
||||
|
||||
Framebuffer::~Framebuffer() {
|
||||
}
|
||||
|
||||
// Pipeline
|
||||
|
||||
Pipeline::Pipeline(Device* device, PipelineBuilder* builder)
|
||||
@@ -842,6 +911,15 @@ namespace metal {
|
||||
[commandBuffer commit];
|
||||
}
|
||||
|
||||
// RenderPass
|
||||
|
||||
RenderPass::RenderPass(Device* device, RenderPassBuilder* builder)
|
||||
: RenderPassBase(builder), device(device) {
|
||||
}
|
||||
|
||||
RenderPass::~RenderPass() {
|
||||
}
|
||||
|
||||
// Sampler
|
||||
|
||||
MTLSamplerMinMagFilter FilterModeToMinMagFilter(nxt::FilterMode mode) {
|
||||
|
||||
Reference in New Issue
Block a user