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:
parent
ca309db58a
commit
68df8b0a3a
|
@ -22,6 +22,8 @@
|
|||
nxt::Device device;
|
||||
nxt::Queue queue;
|
||||
nxt::Pipeline pipeline;
|
||||
nxt::RenderPass renderpass;
|
||||
nxt::Framebuffer framebuffer;
|
||||
|
||||
float RandomFloat(float min, float max) {
|
||||
float zeroOne = rand() / float(RAND_MAX);
|
||||
|
@ -103,7 +105,9 @@ void init() {
|
|||
})"
|
||||
);
|
||||
|
||||
CreateDefaultRenderPass(device, &renderpass, &framebuffer);
|
||||
pipeline = device.CreatePipelineBuilder()
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
.GetResult();
|
||||
|
@ -129,6 +133,7 @@ void frame() {
|
|||
for (int j = 0; j < 50; j++) {
|
||||
|
||||
nxt::CommandBufferBuilder builder = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
.SetPipeline(pipeline)
|
||||
.Clone();
|
||||
|
||||
|
@ -140,6 +145,7 @@ void frame() {
|
|||
i++;
|
||||
}
|
||||
|
||||
builder.EndRenderPass();
|
||||
commands[j] = builder.GetResult();
|
||||
}
|
||||
|
||||
|
|
|
@ -60,6 +60,10 @@ add_executable(HelloCompute HelloCompute.cpp)
|
|||
target_link_libraries(HelloCompute utils)
|
||||
SetCXX14(HelloCompute)
|
||||
|
||||
add_executable(RenderToTexture RenderToTexture.cpp)
|
||||
target_link_libraries(RenderToTexture utils)
|
||||
SetCXX14(RenderToTexture)
|
||||
|
||||
add_executable(Animometer Animometer.cpp)
|
||||
target_link_libraries(Animometer utils)
|
||||
SetCXX14(Animometer)
|
||||
|
|
|
@ -28,6 +28,8 @@ nxt::Buffer modelBuffer;
|
|||
std::array<nxt::Buffer, 2> particleBuffers;
|
||||
|
||||
nxt::Pipeline renderPipeline;
|
||||
nxt::RenderPass renderpass;
|
||||
nxt::Framebuffer framebuffer;
|
||||
|
||||
nxt::Buffer updateParams;
|
||||
nxt::Pipeline updatePipeline;
|
||||
|
@ -134,7 +136,9 @@ void initRender() {
|
|||
.SetInput(1, sizeof(glm::vec2), nxt::InputStepMode::Vertex)
|
||||
.GetResult();
|
||||
|
||||
CreateDefaultRenderPass(device, &renderpass, &framebuffer);
|
||||
renderPipeline = device.CreatePipelineBuilder()
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
.SetInputState(inputState)
|
||||
|
@ -279,11 +283,13 @@ void initCommandBuffers() {
|
|||
.SetBindGroup(0, updateBGs[i])
|
||||
.Dispatch(kNumParticles, 1, 1)
|
||||
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
.SetPipeline(renderPipeline)
|
||||
.TransitionBufferUsage(bufferDst, nxt::BufferUsageBit::Vertex)
|
||||
.SetVertexBuffers(0, 1, &bufferDst, zeroOffsets)
|
||||
.SetVertexBuffers(1, 1, &modelBuffer, zeroOffsets)
|
||||
.DrawArrays(3, kNumParticles, 0, 0)
|
||||
.EndRenderPass()
|
||||
|
||||
.GetResult();
|
||||
}
|
||||
|
|
|
@ -22,6 +22,8 @@ nxt::Queue queue;
|
|||
nxt::Buffer buffer;
|
||||
nxt::Pipeline renderPipeline;
|
||||
nxt::BindGroup renderBindGroup;
|
||||
nxt::RenderPass renderpass;
|
||||
nxt::Framebuffer framebuffer;
|
||||
nxt::Pipeline computePipeline;
|
||||
nxt::BindGroup computeBindGroup;
|
||||
|
||||
|
@ -107,7 +109,9 @@ void init() {
|
|||
.SetBindGroupLayout(0, bgl)
|
||||
.GetResult();
|
||||
|
||||
CreateDefaultRenderPass(device, &renderpass, &framebuffer);
|
||||
renderPipeline = device.CreatePipelineBuilder()
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetLayout(pl)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
|
@ -128,10 +132,12 @@ void frame() {
|
|||
.SetBindGroup(0, computeBindGroup)
|
||||
.Dispatch(1, 1, 1)
|
||||
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
.SetPipeline(renderPipeline)
|
||||
.TransitionBufferUsage(buffer, nxt::BufferUsageBit::Uniform)
|
||||
.SetBindGroup(0, renderBindGroup)
|
||||
.DrawArrays(3, 1, 0, 0)
|
||||
.EndRenderPass()
|
||||
|
||||
.GetResult();
|
||||
|
||||
|
|
|
@ -24,6 +24,8 @@ nxt::Buffer vertexBuffer;
|
|||
|
||||
nxt::Queue queue;
|
||||
nxt::Pipeline pipeline;
|
||||
nxt::RenderPass renderpass;
|
||||
nxt::Framebuffer framebuffer;
|
||||
|
||||
void initBuffers() {
|
||||
static const uint32_t indexData[3] = {
|
||||
|
@ -82,7 +84,9 @@ void init() {
|
|||
.SetInput(0, 4 * sizeof(float), nxt::InputStepMode::Vertex)
|
||||
.GetResult();
|
||||
|
||||
CreateDefaultRenderPass(device, &renderpass, &framebuffer);
|
||||
pipeline = device.CreatePipelineBuilder()
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
.SetInputState(inputState)
|
||||
|
@ -92,10 +96,12 @@ void init() {
|
|||
void frame() {
|
||||
static const uint32_t vertexBufferOffsets[1] = {0};
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
.SetPipeline(pipeline)
|
||||
.SetVertexBuffers(0, 1, &vertexBuffer, vertexBufferOffsets)
|
||||
.SetIndexBuffer(indexBuffer, 0, nxt::IndexFormat::Uint32)
|
||||
.DrawElements(3, 1, 0, 0)
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
queue.Submit(1, &commands);
|
||||
|
|
|
@ -24,6 +24,8 @@ nxt::Buffer instanceBuffer;
|
|||
|
||||
nxt::Queue queue;
|
||||
nxt::Pipeline pipeline;
|
||||
nxt::RenderPass renderpass;
|
||||
nxt::Framebuffer framebuffer;
|
||||
|
||||
void initBuffers() {
|
||||
static const float vertexData[12] = {
|
||||
|
@ -89,7 +91,9 @@ void init() {
|
|||
.SetInput(1, 2 * sizeof(float), nxt::InputStepMode::Instance)
|
||||
.GetResult();
|
||||
|
||||
CreateDefaultRenderPass(device, &renderpass, &framebuffer);
|
||||
pipeline = device.CreatePipelineBuilder()
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
.SetInputState(inputState)
|
||||
|
@ -99,10 +103,12 @@ void init() {
|
|||
void frame() {
|
||||
static const uint32_t vertexBufferOffsets[1] = {0};
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
.SetPipeline(pipeline)
|
||||
.SetVertexBuffers(0, 1, &vertexBuffer, vertexBufferOffsets)
|
||||
.SetVertexBuffers(1, 1, &instanceBuffer, vertexBufferOffsets)
|
||||
.DrawArrays(3, 4, 0, 0)
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
queue.Submit(1, &commands);
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
nxtDevice device;
|
||||
nxtQueue queue;
|
||||
nxtPipeline pipeline;
|
||||
nxtRenderPass renderpass;
|
||||
nxtFramebuffer framebuffer;
|
||||
|
||||
void init() {
|
||||
nxtProcTable procs;
|
||||
|
@ -47,8 +49,25 @@ void init() {
|
|||
"}\n";
|
||||
nxtShaderModule fsModule = CreateShaderModule(device, NXT_SHADER_STAGE_FRAGMENT, fs);
|
||||
|
||||
{
|
||||
nxtRenderPassBuilder builder = nxtDeviceCreateRenderPassBuilder(device);
|
||||
nxtRenderPassBuilderSetAttachmentCount(builder, 1);
|
||||
nxtRenderPassBuilderAttachmentSetFormat(builder, 0, NXT_TEXTURE_FORMAT_R8_G8_B8_A8_UNORM);
|
||||
nxtRenderPassBuilderSetSubpassCount(builder, 1);
|
||||
nxtRenderPassBuilderSubpassSetColorAttachment(builder, 0, 0, 0);
|
||||
renderpass = nxtRenderPassBuilderGetResult(builder);
|
||||
nxtRenderPassBuilderRelease(builder);
|
||||
}
|
||||
{
|
||||
nxtFramebufferBuilder builder = nxtDeviceCreateFramebufferBuilder(device);
|
||||
nxtFramebufferBuilderSetRenderPass(builder, renderpass);
|
||||
nxtFramebufferBuilderSetDimensions(builder, 640, 480);
|
||||
framebuffer = nxtFramebufferBuilderGetResult(builder);
|
||||
nxtFramebufferBuilderRelease(builder);
|
||||
}
|
||||
{
|
||||
nxtPipelineBuilder builder = nxtDeviceCreatePipelineBuilder(device);
|
||||
nxtPipelineBuilderSetSubpass(builder, renderpass, 0);
|
||||
nxtPipelineBuilderSetStage(builder, NXT_SHADER_STAGE_VERTEX, vsModule, "main");
|
||||
nxtPipelineBuilderSetStage(builder, NXT_SHADER_STAGE_FRAGMENT, fsModule, "main");
|
||||
pipeline = nxtPipelineBuilderGetResult(builder);
|
||||
|
@ -63,8 +82,10 @@ void frame() {
|
|||
nxtCommandBuffer commands;
|
||||
{
|
||||
nxtCommandBufferBuilder builder = nxtDeviceCreateCommandBufferBuilder(device);
|
||||
nxtCommandBufferBuilderBeginRenderPass(builder, renderpass, framebuffer);
|
||||
nxtCommandBufferBuilderSetPipeline(builder, pipeline);
|
||||
nxtCommandBufferBuilderDrawArrays(builder, 3, 1, 0, 0);
|
||||
nxtCommandBufferBuilderEndRenderPass(builder);
|
||||
commands = nxtCommandBufferBuilderGetResult(builder);
|
||||
nxtCommandBufferBuilderRelease(builder);
|
||||
}
|
||||
|
|
|
@ -27,6 +27,8 @@ nxt::Sampler sampler;
|
|||
|
||||
nxt::Queue queue;
|
||||
nxt::Pipeline pipeline;
|
||||
nxt::RenderPass renderpass;
|
||||
nxt::Framebuffer framebuffer;
|
||||
nxt::BindGroup bindGroup;
|
||||
|
||||
void initBuffers() {
|
||||
|
@ -135,7 +137,9 @@ void init() {
|
|||
.SetBindGroupLayout(0, bgl)
|
||||
.GetResult();
|
||||
|
||||
CreateDefaultRenderPass(device, &renderpass, &framebuffer);
|
||||
pipeline = device.CreatePipelineBuilder()
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetLayout(pl)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
|
@ -159,11 +163,13 @@ void frame() {
|
|||
if (s.b >= 1.0f) {s.b = 0.0f;}
|
||||
static const uint32_t vertexBufferOffsets[1] = {0};
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
.SetPipeline(pipeline)
|
||||
.SetBindGroup(0, bindGroup)
|
||||
.SetVertexBuffers(0, 1, &vertexBuffer, vertexBufferOffsets)
|
||||
.SetIndexBuffer(indexBuffer, 0, nxt::IndexFormat::Uint32)
|
||||
.DrawElements(3, 1, 0, 0)
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
queue.Submit(1, &commands);
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
nxt::Device device;
|
||||
nxt::Queue queue;
|
||||
nxt::Pipeline pipeline;
|
||||
nxt::RenderPass renderpass;
|
||||
nxt::Framebuffer framebuffer;
|
||||
nxt::Buffer buffer;
|
||||
nxt::BindGroup bindGroup;
|
||||
|
||||
|
@ -59,7 +61,9 @@ void init() {
|
|||
.SetBindGroupLayout(0, bgl)
|
||||
.GetResult();
|
||||
|
||||
CreateDefaultRenderPass(device, &renderpass, &framebuffer);
|
||||
pipeline = device.CreatePipelineBuilder()
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetLayout(pl)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
|
@ -91,10 +95,12 @@ void frame() {
|
|||
buffer.SetSubData(0, sizeof(s) / sizeof(uint32_t), reinterpret_cast<uint32_t*>(&s));
|
||||
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
.SetPipeline(pipeline)
|
||||
.TransitionBufferUsage(buffer, nxt::BufferUsageBit::Uniform)
|
||||
.SetBindGroup(0, bindGroup)
|
||||
.DrawArrays(3, 1, 0, 0)
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
queue.Submit(1, &commands);
|
||||
|
|
|
@ -23,6 +23,8 @@ nxt::Buffer vertexBuffer;
|
|||
|
||||
nxt::Queue queue;
|
||||
nxt::Pipeline pipeline;
|
||||
nxt::RenderPass renderpass;
|
||||
nxt::Framebuffer framebuffer;
|
||||
|
||||
void initBuffers() {
|
||||
static const float vertexData[12] = {
|
||||
|
@ -59,7 +61,7 @@ void init() {
|
|||
|
||||
nxt::ShaderModule fsModule = CreateShaderModule(device, nxt::ShaderStage::Fragment, R"(
|
||||
#version 450
|
||||
out vec4 fragColor;
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
void main() {
|
||||
fragColor = vec4(1.0, 0.0, 0.0, 1.0);
|
||||
})"
|
||||
|
@ -70,7 +72,9 @@ void init() {
|
|||
.SetInput(0, 4 * sizeof(float), nxt::InputStepMode::Vertex)
|
||||
.GetResult();
|
||||
|
||||
CreateDefaultRenderPass(device, &renderpass, &framebuffer);
|
||||
pipeline = device.CreatePipelineBuilder()
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
.SetInputState(inputState)
|
||||
|
@ -80,9 +84,11 @@ void init() {
|
|||
void frame() {
|
||||
static const uint32_t vertexBufferOffsets[1] = {0};
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
.SetPipeline(pipeline)
|
||||
.SetVertexBuffers(0, 1, &vertexBuffer, vertexBufferOffsets)
|
||||
.DrawArrays(3, 1, 0, 0)
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
queue.Submit(1, &commands);
|
||||
|
|
|
@ -0,0 +1,235 @@
|
|||
// Copyright 2017 The NXT Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "Utils.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <vector>
|
||||
|
||||
nxt::Device device;
|
||||
|
||||
nxt::Buffer vertexBuffer;
|
||||
nxt::Buffer vertexBufferQuad;
|
||||
|
||||
nxt::Texture renderTarget;
|
||||
nxt::TextureView renderTargetView;
|
||||
nxt::Sampler samplerPost;
|
||||
|
||||
nxt::Queue queue;
|
||||
nxt::Pipeline pipeline;
|
||||
nxt::Pipeline pipelinePost;
|
||||
nxt::BindGroup bindGroup;
|
||||
nxt::RenderPass renderpass;
|
||||
nxt::Framebuffer framebuffer;
|
||||
|
||||
void initBuffers() {
|
||||
static const float vertexData[12] = {
|
||||
0.0f, 0.5f, 0.0f, 1.0f,
|
||||
-0.5f, -0.5f, 0.0f, 1.0f,
|
||||
0.5f, -0.5f, 0.0f, 1.0f,
|
||||
};
|
||||
vertexBuffer = device.CreateBufferBuilder()
|
||||
.SetAllowedUsage(nxt::BufferUsageBit::Mapped | nxt::BufferUsageBit::Vertex)
|
||||
.SetInitialUsage(nxt::BufferUsageBit::Mapped)
|
||||
.SetSize(sizeof(vertexData))
|
||||
.GetResult();
|
||||
vertexBuffer.SetSubData(0, sizeof(vertexData) / sizeof(uint32_t),
|
||||
reinterpret_cast<const uint32_t*>(vertexData));
|
||||
vertexBuffer.FreezeUsage(nxt::BufferUsageBit::Vertex);
|
||||
|
||||
static const float vertexDataQuad[24] = {
|
||||
-1.0f, -1.0f, 0.0f, 1.0f,
|
||||
-1.0f, 1.0f, 0.0f, 1.0f,
|
||||
1.0f, -1.0f, 0.0f, 1.0f,
|
||||
-1.0f, 1.0f, 0.0f, 1.0f,
|
||||
1.0f, -1.0f, 0.0f, 1.0f,
|
||||
1.0f, 1.0f, 0.0f, 1.0f,
|
||||
};
|
||||
vertexBufferQuad = device.CreateBufferBuilder()
|
||||
.SetAllowedUsage(nxt::BufferUsageBit::Mapped | nxt::BufferUsageBit::Vertex)
|
||||
.SetInitialUsage(nxt::BufferUsageBit::Mapped)
|
||||
.SetSize(sizeof(vertexDataQuad))
|
||||
.GetResult();
|
||||
vertexBufferQuad.SetSubData(0, sizeof(vertexDataQuad) / sizeof(uint32_t),
|
||||
reinterpret_cast<const uint32_t*>(vertexDataQuad));
|
||||
vertexBufferQuad.FreezeUsage(nxt::BufferUsageBit::Vertex);
|
||||
}
|
||||
|
||||
void initTextures() {
|
||||
renderTarget = device.CreateTextureBuilder()
|
||||
.SetDimension(nxt::TextureDimension::e2D)
|
||||
.SetExtent(640, 480, 1)
|
||||
.SetFormat(nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetMipLevels(1)
|
||||
.SetAllowedUsage(nxt::TextureUsageBit::ColorAttachment | nxt::TextureUsageBit::Sampled)
|
||||
.SetInitialUsage(nxt::TextureUsageBit::ColorAttachment)
|
||||
.GetResult();
|
||||
renderTargetView = renderTarget.CreateTextureViewBuilder().GetResult();
|
||||
|
||||
samplerPost = device.CreateSamplerBuilder()
|
||||
.SetFilterMode(nxt::FilterMode::Linear, nxt::FilterMode::Linear, nxt::FilterMode::Linear)
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
void initRenderPass() {
|
||||
renderpass = device.CreateRenderPassBuilder()
|
||||
.SetAttachmentCount(2)
|
||||
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.AttachmentSetFormat(1, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetSubpassCount(2)
|
||||
// subpass 0
|
||||
.SubpassSetColorAttachment(0, 0, 0) // -> render target
|
||||
// subpass 1
|
||||
.SubpassSetColorAttachment(1, 0, 1) // -> back buffer
|
||||
.GetResult();
|
||||
framebuffer = device.CreateFramebufferBuilder()
|
||||
.SetRenderPass(renderpass)
|
||||
// attachment 0 -> render target
|
||||
.SetAttachment(0, renderTargetView)
|
||||
// attachment 1 -> back buffer
|
||||
// (implicit) // TODO(kainino@chromium.org): use the texture provided by WSI
|
||||
.SetDimensions(640, 480)
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
void initPipeline() {
|
||||
nxt::ShaderModule vsModule = CreateShaderModule(device, nxt::ShaderStage::Vertex, R"(
|
||||
#version 450
|
||||
layout(location = 0) in vec4 pos;
|
||||
void main() {
|
||||
gl_Position = pos;
|
||||
})"
|
||||
);
|
||||
|
||||
nxt::ShaderModule fsModule = CreateShaderModule(device, nxt::ShaderStage::Fragment, R"(
|
||||
#version 450
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
void main() {
|
||||
fragColor = vec4(1.0, 0.0, 0.0, 1.0);
|
||||
})"
|
||||
);
|
||||
|
||||
auto inputState = device.CreateInputStateBuilder()
|
||||
.SetAttribute(0, 0, nxt::VertexFormat::FloatR32G32B32A32, 0)
|
||||
.SetInput(0, 4 * sizeof(float), nxt::InputStepMode::Vertex)
|
||||
.GetResult();
|
||||
|
||||
pipeline = device.CreatePipelineBuilder()
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
.SetInputState(inputState)
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
void initPipelinePost() {
|
||||
nxt::ShaderModule vsModule = CreateShaderModule(device, nxt::ShaderStage::Vertex, R"(
|
||||
#version 450
|
||||
layout(location = 0) in vec4 pos;
|
||||
void main() {
|
||||
gl_Position = pos;
|
||||
})"
|
||||
);
|
||||
|
||||
nxt::ShaderModule fsModule = CreateShaderModule(device, nxt::ShaderStage::Fragment, R"(
|
||||
#version 450
|
||||
layout(set = 0, binding = 0) uniform sampler samp;
|
||||
layout(set = 0, binding = 1) uniform texture2D tex;
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
void main() {
|
||||
fragColor = texture(sampler2D(tex, samp), gl_FragCoord.xy / vec2(640.0, 480.0)) + vec4(0.0, 0.0, 0.5, 0.0);
|
||||
})"
|
||||
);
|
||||
|
||||
auto inputState = device.CreateInputStateBuilder()
|
||||
.SetAttribute(0, 0, nxt::VertexFormat::FloatR32G32B32A32, 0)
|
||||
.SetInput(0, 4 * sizeof(float), nxt::InputStepMode::Vertex)
|
||||
.GetResult();
|
||||
|
||||
nxt::BindGroupLayout bgl = device.CreateBindGroupLayoutBuilder()
|
||||
.SetBindingsType(nxt::ShaderStageBit::Fragment, nxt::BindingType::Sampler, 0, 1)
|
||||
.SetBindingsType(nxt::ShaderStageBit::Fragment, nxt::BindingType::SampledTexture, 1, 1)
|
||||
.GetResult();
|
||||
|
||||
nxt::PipelineLayout pl = device.CreatePipelineLayoutBuilder()
|
||||
.SetBindGroupLayout(0, bgl)
|
||||
.GetResult();
|
||||
|
||||
pipelinePost = device.CreatePipelineBuilder()
|
||||
.SetSubpass(renderpass, 1)
|
||||
.SetLayout(pl)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
.SetInputState(inputState)
|
||||
.GetResult();
|
||||
|
||||
bindGroup = device.CreateBindGroupBuilder()
|
||||
.SetLayout(bgl)
|
||||
.SetUsage(nxt::BindGroupUsage::Frozen)
|
||||
.SetSamplers(0, 1, &samplerPost)
|
||||
.SetTextureViews(1, 1, &renderTargetView)
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
void init() {
|
||||
nxtProcTable procs;
|
||||
GetProcTableAndDevice(&procs, &device);
|
||||
nxtSetProcs(&procs);
|
||||
|
||||
queue = device.CreateQueueBuilder().GetResult();
|
||||
|
||||
initBuffers();
|
||||
initTextures();
|
||||
initRenderPass();
|
||||
initPipeline();
|
||||
initPipelinePost();
|
||||
}
|
||||
|
||||
void frame() {
|
||||
static const uint32_t vertexBufferOffsets[1] = {0};
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
// renderTarget is not transitioned here because it's implicit in
|
||||
// BeginRenderPass or AdvanceSubpass.
|
||||
.SetPipeline(pipeline)
|
||||
.SetVertexBuffers(0, 1, &vertexBuffer, vertexBufferOffsets)
|
||||
.DrawArrays(3, 1, 0, 0)
|
||||
.AdvanceSubpass()
|
||||
// renderTarget must be transitioned here because it's Sampled, not
|
||||
// ColorAttachment or InputAttachment.
|
||||
.TransitionTextureUsage(renderTarget, nxt::TextureUsageBit::Sampled)
|
||||
.SetPipeline(pipelinePost)
|
||||
.SetBindGroup(0, bindGroup)
|
||||
.SetVertexBuffers(0, 1, &vertexBufferQuad, vertexBufferOffsets)
|
||||
.DrawArrays(6, 1, 0, 0)
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
queue.Submit(1, &commands);
|
||||
SwapBuffers();
|
||||
}
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
if (!InitUtils(argc, argv)) {
|
||||
return 1;
|
||||
}
|
||||
init();
|
||||
|
||||
while (!ShouldQuit()) {
|
||||
frame();
|
||||
usleep(16000);
|
||||
}
|
||||
|
||||
// TODO release stuff
|
||||
}
|
|
@ -200,6 +200,19 @@ nxt::ShaderModule CreateShaderModule(const nxt::Device& device, nxt::ShaderStage
|
|||
.GetResult();
|
||||
}
|
||||
|
||||
void CreateDefaultRenderPass(const nxt::Device& device, nxt::RenderPass* renderPass, nxt::Framebuffer* framebuffer) {
|
||||
*renderPass = device.CreateRenderPassBuilder()
|
||||
.SetAttachmentCount(1)
|
||||
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetSubpassCount(1)
|
||||
.SubpassSetColorAttachment(0, 0, 0)
|
||||
.GetResult();
|
||||
*framebuffer = device.CreateFramebufferBuilder()
|
||||
.SetRenderPass(*renderPass)
|
||||
.SetDimensions(640, 480)
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
bool InitUtils(int argc, const char** argv) {
|
||||
for (int i = 0; i < argc; i++) {
|
||||
|
|
|
@ -32,6 +32,7 @@ extern "C" {
|
|||
#include <nxt/nxtcpp.h>
|
||||
void GetProcTableAndDevice(nxtProcTable* procs, nxt::Device* device);
|
||||
nxt::ShaderModule CreateShaderModule(const nxt::Device& device, nxt::ShaderStage stage, const char* source);
|
||||
void CreateDefaultRenderPass(const nxt::Device& device, nxt::RenderPass* renderPass, nxt::Framebuffer* framebuffer);
|
||||
#else
|
||||
void GetProcTableAndDevice(nxtProcTable* procs, nxtDevice* device);
|
||||
nxtShaderModule CreateShaderModule(nxtDevice device, nxtShaderStage stage, const char* source);
|
||||
|
|
104
next.json
104
next.json
|
@ -218,6 +218,19 @@
|
|||
"name": "get result",
|
||||
"returns": "command buffer"
|
||||
},
|
||||
{
|
||||
"name": "begin render pass",
|
||||
"args": [
|
||||
{"name": "render pass", "type": "render pass"},
|
||||
{"name": "framebuffer", "type": "framebuffer"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "advance subpass"
|
||||
},
|
||||
{
|
||||
"name": "end render pass"
|
||||
},
|
||||
{
|
||||
"name": "copy buffer to texture",
|
||||
"args": [
|
||||
|
@ -347,6 +360,10 @@
|
|||
"name": "create command buffer builder",
|
||||
"returns": "command buffer builder"
|
||||
},
|
||||
{
|
||||
"name": "create framebuffer builder",
|
||||
"returns": "framebuffer builder"
|
||||
},
|
||||
{
|
||||
"name": "create input state builder",
|
||||
"returns": "input state builder"
|
||||
|
@ -363,6 +380,10 @@
|
|||
"name": "create queue builder",
|
||||
"returns": "queue builder"
|
||||
},
|
||||
{
|
||||
"name": "create render pass builder",
|
||||
"returns": "render pass builder"
|
||||
},
|
||||
{
|
||||
"name": "create sampler builder",
|
||||
"returns": "sampler builder"
|
||||
|
@ -403,6 +424,38 @@
|
|||
{"value": 1, "name":"linear"}
|
||||
]
|
||||
},
|
||||
"framebuffer": {
|
||||
"category": "object"
|
||||
},
|
||||
"framebuffer builder": {
|
||||
"category": "object",
|
||||
"methods": [
|
||||
{
|
||||
"name": "get result",
|
||||
"returns": "framebuffer"
|
||||
},
|
||||
{
|
||||
"name": "set render pass",
|
||||
"args": [
|
||||
{"name": "render pass", "type": "render pass"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "set dimensions",
|
||||
"args": [
|
||||
{"name": "width", "type": "uint32_t"},
|
||||
{"name": "height", "type": "uint32_t"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "set attachment",
|
||||
"args": [
|
||||
{"name": "attachment slot", "type": "uint32_t"},
|
||||
{"name": "texture views", "type": "texture view"}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"index format": {
|
||||
"category": "enum",
|
||||
"values": [
|
||||
|
@ -462,6 +515,13 @@
|
|||
{"name": "layout", "type": "pipeline layout"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "set subpass",
|
||||
"args": [
|
||||
{"name": "render pass", "type": "render pass"},
|
||||
{"name": "subpass", "type": "uint32_t"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "set stage",
|
||||
"args": [
|
||||
|
@ -518,6 +578,50 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"render pass builder": {
|
||||
"category": "object",
|
||||
"TODO": {
|
||||
"attachments": "Also need load op, store op, depth/stencil attachments and depth/stencil ops, and maybe usages for the implicit attachment transitions",
|
||||
"subpasses": "Also need input attachments, resolve attachments, and preserve attachments"
|
||||
},
|
||||
"methods": [
|
||||
{
|
||||
"name": "get result",
|
||||
"returns": "render pass"
|
||||
},
|
||||
{
|
||||
"name": "set attachment count",
|
||||
"args": [
|
||||
{"name": "attachment count", "type": "uint32_t"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "attachment set format",
|
||||
"TODO": "Also need sample count",
|
||||
"args": [
|
||||
{"name": "attachment slot", "type": "uint32_t"},
|
||||
{"name": "format", "type": "texture format"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "set subpass count",
|
||||
"args": [
|
||||
{"name": "subpass count", "type": "uint32_t"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "subpass set color attachment",
|
||||
"args": [
|
||||
{"name": "subpass index", "type": "uint32_t"},
|
||||
{"name": "output attachment location", "type": "uint32_t"},
|
||||
{"name": "attachment slot", "type": "uint32_t"}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"render pass": {
|
||||
"category": "object"
|
||||
},
|
||||
"sampler": {
|
||||
"category": "object"
|
||||
},
|
||||
|
|
|
@ -34,6 +34,8 @@ list(APPEND BACKEND_SOURCES
|
|||
${COMMON_DIR}/Device.cpp
|
||||
${COMMON_DIR}/Device.h
|
||||
${COMMON_DIR}/Forward.h
|
||||
${COMMON_DIR}/Framebuffer.cpp
|
||||
${COMMON_DIR}/Framebuffer.h
|
||||
${COMMON_DIR}/InputState.cpp
|
||||
${COMMON_DIR}/InputState.h
|
||||
${COMMON_DIR}/Math.cpp
|
||||
|
@ -46,6 +48,8 @@ list(APPEND BACKEND_SOURCES
|
|||
${COMMON_DIR}/PipelineLayout.h
|
||||
${COMMON_DIR}/Queue.cpp
|
||||
${COMMON_DIR}/Queue.h
|
||||
${COMMON_DIR}/RenderPass.cpp
|
||||
${COMMON_DIR}/RenderPass.h
|
||||
${COMMON_DIR}/RefCounted.cpp
|
||||
${COMMON_DIR}/RefCounted.h
|
||||
${COMMON_DIR}/Sampler.cpp
|
||||
|
|
|
@ -114,12 +114,14 @@ namespace backend {
|
|||
HandleError("Setting bindings type over maximum number of bindings");
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = start; i < start + count; i++) {
|
||||
if (bindingInfo.mask[i]) {
|
||||
HandleError("Setting already set binding type");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = start; i < start + count; i++) {
|
||||
bindingInfo.mask.set(i);
|
||||
bindingInfo.visibilities[i] = visibility;
|
||||
bindingInfo.types[i] = bindingType;
|
||||
|
|
|
@ -55,6 +55,18 @@ namespace backend {
|
|||
Command type;
|
||||
while(commands->NextCommandId(&type)) {
|
||||
switch (type) {
|
||||
case Command::AdvanceSubpass:
|
||||
{
|
||||
AdvanceSubpassCmd* cmd = commands->NextCommand<AdvanceSubpassCmd>();
|
||||
cmd->~AdvanceSubpassCmd();
|
||||
}
|
||||
break;
|
||||
case Command::BeginRenderPass:
|
||||
{
|
||||
BeginRenderPassCmd* begin = commands->NextCommand<BeginRenderPassCmd>();
|
||||
begin->~BeginRenderPassCmd();
|
||||
}
|
||||
break;
|
||||
case Command::CopyBufferToTexture:
|
||||
{
|
||||
CopyBufferToTextureCmd* copy = commands->NextCommand<CopyBufferToTextureCmd>();
|
||||
|
@ -79,6 +91,12 @@ namespace backend {
|
|||
draw->~DrawElementsCmd();
|
||||
}
|
||||
break;
|
||||
case Command::EndRenderPass:
|
||||
{
|
||||
EndRenderPassCmd* cmd = commands->NextCommand<EndRenderPassCmd>();
|
||||
cmd->~EndRenderPassCmd();
|
||||
}
|
||||
break;
|
||||
case Command::SetPipeline:
|
||||
{
|
||||
SetPipelineCmd* cmd = commands->NextCommand<SetPipelineCmd>();
|
||||
|
@ -148,6 +166,7 @@ namespace backend {
|
|||
VALIDATION_ASPECT_BINDGROUPS,
|
||||
VALIDATION_ASPECT_VERTEX_BUFFERS,
|
||||
VALIDATION_ASPECT_INDEX_BUFFER,
|
||||
VALIDATION_ASPECT_RENDER_PASS,
|
||||
|
||||
VALIDATION_ASPECT_COUNT,
|
||||
};
|
||||
|
@ -162,6 +181,7 @@ namespace backend {
|
|||
std::bitset<kMaxVertexInputs> inputsSet;
|
||||
PipelineBase* lastPipeline = nullptr;
|
||||
|
||||
// TODO(kainino@chromium.org): Manage this state inside an object, change lambdas to methods
|
||||
std::map<BufferBase*, nxt::BufferUsageBit> mostRecentBufferUsages;
|
||||
auto bufferHasGuaranteedUsageBit = [&](BufferBase* buffer, nxt::BufferUsageBit usage) -> bool {
|
||||
assert(usage != nxt::BufferUsageBit::None && nxt::HasZeroOrOneBits(usage));
|
||||
|
@ -234,9 +254,84 @@ namespace backend {
|
|||
return true;
|
||||
};
|
||||
|
||||
// TODO(kainino@chromium.org): Manage this state inside an object, change lambda to a method
|
||||
RenderPassBase* currentRenderPass = nullptr;
|
||||
FramebufferBase* currentFramebuffer = nullptr;
|
||||
uint32_t currentSubpass = 0;
|
||||
auto beginSubpass = [&]() -> bool {
|
||||
auto& subpassInfo = currentRenderPass->GetSubpassInfo(currentSubpass);
|
||||
for (auto attachmentSlot : subpassInfo.colorAttachments) {
|
||||
auto* tv = currentFramebuffer->GetTextureView(attachmentSlot);
|
||||
// TODO(kainino@chromium.org): the TextureView can only be null
|
||||
// because of the null=backbuffer hack (null representing the
|
||||
// backbuffer). Once that hack is removed (once we have WSI)
|
||||
// this check isn't needed.
|
||||
if (tv == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto* texture = tv->GetTexture();
|
||||
if (texture->HasFrozenUsage(nxt::TextureUsageBit::ColorAttachment)) {
|
||||
continue;
|
||||
}
|
||||
if (!texture->IsTransitionPossible(nxt::TextureUsageBit::ColorAttachment)) {
|
||||
HandleError("Can't transition attachment to ColorAttachment usage");
|
||||
return false;
|
||||
}
|
||||
mostRecentTextureUsages.erase(texture);
|
||||
texturesTransitioned.insert(texture);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
Command type;
|
||||
while(iterator.NextCommandId(&type)) {
|
||||
switch (type) {
|
||||
case Command::AdvanceSubpass:
|
||||
{
|
||||
iterator.NextCommand<AdvanceSubpassCmd>();
|
||||
if (currentRenderPass == nullptr) {
|
||||
HandleError("Can't advance subpass without an active render pass");
|
||||
return false;
|
||||
}
|
||||
if (currentSubpass + 1 >= currentRenderPass->GetSubpassCount()) {
|
||||
HandleError("Can't advance beyond the last subpass");
|
||||
return false;
|
||||
}
|
||||
currentSubpass += 1;
|
||||
if (!beginSubpass()) {
|
||||
return false;
|
||||
}
|
||||
aspects.reset(VALIDATION_ASPECT_RENDER_PIPELINE);
|
||||
}
|
||||
break;
|
||||
|
||||
case Command::BeginRenderPass:
|
||||
{
|
||||
BeginRenderPassCmd* begin = iterator.NextCommand<BeginRenderPassCmd>();
|
||||
auto* renderPass = begin->renderPass.Get();
|
||||
auto* framebuffer = begin->framebuffer.Get();
|
||||
if (currentRenderPass != nullptr) {
|
||||
HandleError("A render pass is already active");
|
||||
return false;
|
||||
}
|
||||
if (!framebuffer->GetRenderPass()->IsCompatibleWith(renderPass)) {
|
||||
HandleError("Framebuffer is incompatible with this render pass");
|
||||
return false;
|
||||
}
|
||||
|
||||
aspects.reset(VALIDATION_ASPECT_COMPUTE_PIPELINE);
|
||||
aspects.reset(VALIDATION_ASPECT_RENDER_PIPELINE);
|
||||
aspects.set(VALIDATION_ASPECT_RENDER_PASS);
|
||||
currentRenderPass = renderPass;
|
||||
currentFramebuffer = framebuffer;
|
||||
currentSubpass = 0;
|
||||
if (!beginSubpass()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Command::CopyBufferToTexture:
|
||||
{
|
||||
CopyBufferToTextureCmd* copy = iterator.NextCommand<CopyBufferToTextureCmd>();
|
||||
|
@ -251,6 +346,11 @@ namespace backend {
|
|||
uint64_t z = copy->z;
|
||||
uint32_t level = copy->level;
|
||||
|
||||
if (currentRenderPass) {
|
||||
HandleError("Blit cannot occur during a render pass");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!bufferHasGuaranteedUsageBit(buffer, nxt::BufferUsageBit::TransferSrc)) {
|
||||
HandleError("Buffer needs the transfer source usage bit");
|
||||
return false;
|
||||
|
@ -354,6 +454,24 @@ namespace backend {
|
|||
}
|
||||
break;
|
||||
|
||||
case Command::EndRenderPass:
|
||||
{
|
||||
iterator.NextCommand<EndRenderPassCmd>();
|
||||
if (currentRenderPass == nullptr) {
|
||||
HandleError("No render pass is currently active");
|
||||
return false;
|
||||
}
|
||||
if (currentSubpass < currentRenderPass->GetSubpassCount() - 1) {
|
||||
HandleError("Can't end a render pass before the last subpass");
|
||||
return false;
|
||||
}
|
||||
currentRenderPass = nullptr;
|
||||
currentFramebuffer = nullptr;
|
||||
aspects.reset(VALIDATION_ASPECT_RENDER_PASS);
|
||||
aspects.reset(VALIDATION_ASPECT_RENDER_PIPELINE);
|
||||
}
|
||||
break;
|
||||
|
||||
case Command::SetPipeline:
|
||||
{
|
||||
SetPipelineCmd* cmd = iterator.NextCommand<SetPipelineCmd>();
|
||||
|
@ -361,11 +479,21 @@ namespace backend {
|
|||
PipelineLayoutBase* layout = pipeline->GetLayout();
|
||||
|
||||
if (pipeline->IsCompute()) {
|
||||
if (currentRenderPass) {
|
||||
HandleError("Can't use a compute pipeline while a render pass is active");
|
||||
return false;
|
||||
}
|
||||
aspects.set(VALIDATION_ASPECT_COMPUTE_PIPELINE);
|
||||
aspects.reset(VALIDATION_ASPECT_RENDER_PIPELINE);
|
||||
} else {
|
||||
if (!currentRenderPass) {
|
||||
HandleError("A render pass must be active when a render pipeline is set");
|
||||
return false;
|
||||
}
|
||||
if (!pipeline->GetRenderPass()->IsCompatibleWith(currentRenderPass)) {
|
||||
HandleError("Pipeline is incompatible with this render pass");
|
||||
return false;
|
||||
}
|
||||
aspects.set(VALIDATION_ASPECT_RENDER_PIPELINE);
|
||||
aspects.reset(VALIDATION_ASPECT_COMPUTE_PIPELINE);
|
||||
}
|
||||
aspects.reset(VALIDATION_ASPECT_BINDGROUPS);
|
||||
aspects.reset(VALIDATION_ASPECT_VERTEX_BUFFERS);
|
||||
|
@ -472,6 +600,29 @@ namespace backend {
|
|||
return false;
|
||||
}
|
||||
|
||||
// TODO(kainino@chromium.org): We should be able to
|
||||
// optimize this by tracking which textures are in use
|
||||
// as attachments. Maybe it's possible that the
|
||||
// XAttachment usages could mark this: disallow
|
||||
// explicit transitions to XAttachment usages, and
|
||||
// disallow explicit transitions of resources already
|
||||
// in an XAttachment usage.
|
||||
if (currentRenderPass) {
|
||||
auto& info = currentRenderPass->GetSubpassInfo(currentSubpass);
|
||||
for (uint32_t location = 0; location < info.colorAttachments.size(); ++location) {
|
||||
if (!info.colorAttachmentsSet[location]) {
|
||||
continue;
|
||||
}
|
||||
uint32_t attachmentSlot = info.colorAttachments[location];
|
||||
auto* tv = currentFramebuffer->GetTextureView(attachmentSlot);
|
||||
// TODO(kainino@chromium.org): remove check for tv being non-null once the null=backbuffer hack is removed.
|
||||
if (tv && tv->GetTexture() == texture) {
|
||||
HandleError("Can't transition a texture while it's used as a color attachment");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mostRecentTextureUsages[texture] = usage;
|
||||
|
||||
texturesTransitioned.insert(texture);
|
||||
|
@ -494,6 +645,17 @@ namespace backend {
|
|||
return device->CreateCommandBuffer(this);
|
||||
}
|
||||
|
||||
void CommandBufferBuilder::AdvanceSubpass() {
|
||||
allocator.Allocate<AdvanceSubpassCmd>(Command::AdvanceSubpass);
|
||||
}
|
||||
|
||||
void CommandBufferBuilder::BeginRenderPass(RenderPassBase* renderPass, FramebufferBase* framebuffer) {
|
||||
BeginRenderPassCmd* cmd = allocator.Allocate<BeginRenderPassCmd>(Command::BeginRenderPass);
|
||||
new(cmd) BeginRenderPassCmd;
|
||||
cmd->renderPass = renderPass;
|
||||
cmd->framebuffer = framebuffer;
|
||||
}
|
||||
|
||||
void CommandBufferBuilder::CopyBufferToTexture(BufferBase* buffer, uint32_t bufferOffset,
|
||||
TextureBase* texture, uint32_t x, uint32_t y, uint32_t z,
|
||||
uint32_t width, uint32_t height, uint32_t depth, uint32_t level) {
|
||||
|
@ -537,6 +699,10 @@ namespace backend {
|
|||
draw->firstInstance = firstInstance;
|
||||
}
|
||||
|
||||
void CommandBufferBuilder::EndRenderPass() {
|
||||
allocator.Allocate<EndRenderPassCmd>(Command::EndRenderPass);
|
||||
}
|
||||
|
||||
void CommandBufferBuilder::SetPipeline(PipelineBase* pipeline) {
|
||||
SetPipelineCmd* cmd = allocator.Allocate<SetPipelineCmd>(Command::SetPipeline);
|
||||
new(cmd) SetPipelineCmd;
|
||||
|
|
|
@ -28,8 +28,10 @@ namespace backend {
|
|||
|
||||
class BindGroupBase;
|
||||
class BufferBase;
|
||||
class FramebufferBase;
|
||||
class DeviceBase;
|
||||
class PipelineBase;
|
||||
class RenderPassBase;
|
||||
class TextureBase;
|
||||
|
||||
class CommandBufferBuilder;
|
||||
|
@ -55,12 +57,15 @@ namespace backend {
|
|||
CommandIterator AcquireCommands();
|
||||
|
||||
// NXT API
|
||||
void AdvanceSubpass();
|
||||
void BeginRenderPass(RenderPassBase* renderPass, FramebufferBase* framebuffer);
|
||||
void CopyBufferToTexture(BufferBase* buffer, uint32_t bufferOffset,
|
||||
TextureBase* texture, uint32_t x, uint32_t y, uint32_t z,
|
||||
uint32_t width, uint32_t height, uint32_t depth, uint32_t level);
|
||||
void Dispatch(uint32_t x, uint32_t y, uint32_t z);
|
||||
void DrawArrays(uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance);
|
||||
void DrawElements(uint32_t vertexCount, uint32_t instanceCount, uint32_t firstIndex, uint32_t firstInstance);
|
||||
void EndRenderPass();
|
||||
void SetPushConstants(nxt::ShaderStageBit stage, uint32_t offset, uint32_t count, const void* data);
|
||||
void SetPipeline(PipelineBase* pipeline);
|
||||
void SetBindGroup(uint32_t groupIndex, BindGroupBase* group);
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
#ifndef BACKEND_COMMON_COMMANDS_H_
|
||||
#define BACKEND_COMMON_COMMANDS_H_
|
||||
|
||||
#include "Framebuffer.h"
|
||||
#include "RenderPass.h"
|
||||
#include "Texture.h"
|
||||
|
||||
#include "nxt/nxtcpp.h"
|
||||
|
@ -26,10 +28,13 @@ namespace backend {
|
|||
// dependencies: Ref<Object> needs Object to be defined.
|
||||
|
||||
enum class Command {
|
||||
AdvanceSubpass,
|
||||
BeginRenderPass,
|
||||
CopyBufferToTexture,
|
||||
Dispatch,
|
||||
DrawArrays,
|
||||
DrawElements,
|
||||
EndRenderPass,
|
||||
SetPipeline,
|
||||
SetPushConstants,
|
||||
SetBindGroup,
|
||||
|
@ -39,6 +44,14 @@ namespace backend {
|
|||
TransitionTextureUsage,
|
||||
};
|
||||
|
||||
struct AdvanceSubpassCmd {
|
||||
};
|
||||
|
||||
struct BeginRenderPassCmd {
|
||||
Ref<RenderPassBase> renderPass;
|
||||
Ref<FramebufferBase> framebuffer;
|
||||
};
|
||||
|
||||
struct CopyBufferToTextureCmd {
|
||||
Ref<BufferBase> buffer;
|
||||
uint32_t bufferOffset;
|
||||
|
@ -68,6 +81,9 @@ namespace backend {
|
|||
uint32_t firstInstance;
|
||||
};
|
||||
|
||||
struct EndRenderPassCmd {
|
||||
};
|
||||
|
||||
struct SetPipelineCmd {
|
||||
Ref<PipelineBase> pipeline;
|
||||
};
|
||||
|
|
|
@ -18,10 +18,12 @@
|
|||
#include "BindGroupLayout.h"
|
||||
#include "Buffer.h"
|
||||
#include "CommandBuffer.h"
|
||||
#include "Framebuffer.h"
|
||||
#include "InputState.h"
|
||||
#include "Pipeline.h"
|
||||
#include "PipelineLayout.h"
|
||||
#include "Queue.h"
|
||||
#include "RenderPass.h"
|
||||
#include "Sampler.h"
|
||||
#include "ShaderModule.h"
|
||||
#include "Texture.h"
|
||||
|
@ -96,6 +98,9 @@ namespace backend {
|
|||
CommandBufferBuilder* DeviceBase::CreateCommandBufferBuilder() {
|
||||
return new CommandBufferBuilder(this);
|
||||
}
|
||||
FramebufferBuilder* DeviceBase::CreateFramebufferBuilder() {
|
||||
return new FramebufferBuilder(this);
|
||||
}
|
||||
InputStateBuilder* DeviceBase::CreateInputStateBuilder() {
|
||||
return new InputStateBuilder(this);
|
||||
}
|
||||
|
@ -108,6 +113,9 @@ namespace backend {
|
|||
QueueBuilder* DeviceBase::CreateQueueBuilder() {
|
||||
return new QueueBuilder(this);
|
||||
}
|
||||
RenderPassBuilder* DeviceBase::CreateRenderPassBuilder() {
|
||||
return new RenderPassBuilder(this);
|
||||
}
|
||||
SamplerBuilder* DeviceBase::CreateSamplerBuilder() {
|
||||
return new SamplerBuilder(this);
|
||||
}
|
||||
|
|
|
@ -40,10 +40,12 @@ namespace backend {
|
|||
virtual BufferBase* CreateBuffer(BufferBuilder* builder) = 0;
|
||||
virtual BufferViewBase* CreateBufferView(BufferViewBuilder* builder) = 0;
|
||||
virtual CommandBufferBase* CreateCommandBuffer(CommandBufferBuilder* builder) = 0;
|
||||
virtual FramebufferBase* CreateFramebuffer(FramebufferBuilder* builder) = 0;
|
||||
virtual InputStateBase* CreateInputState(InputStateBuilder* builder) = 0;
|
||||
virtual PipelineBase* CreatePipeline(PipelineBuilder* builder) = 0;
|
||||
virtual PipelineLayoutBase* CreatePipelineLayout(PipelineLayoutBuilder* builder) = 0;
|
||||
virtual QueueBase* CreateQueue(QueueBuilder* builder) = 0;
|
||||
virtual RenderPassBase* CreateRenderPass(RenderPassBuilder* builder) = 0;
|
||||
virtual SamplerBase* CreateSampler(SamplerBuilder* builder) = 0;
|
||||
virtual ShaderModuleBase* CreateShaderModule(ShaderModuleBuilder* builder) = 0;
|
||||
virtual TextureBase* CreateTexture(TextureBuilder* builder) = 0;
|
||||
|
@ -72,10 +74,12 @@ namespace backend {
|
|||
BufferBuilder* CreateBufferBuilder();
|
||||
BufferViewBuilder* CreateBufferViewBuilder();
|
||||
CommandBufferBuilder* CreateCommandBufferBuilder();
|
||||
FramebufferBuilder* CreateFramebufferBuilder();
|
||||
InputStateBuilder* CreateInputStateBuilder();
|
||||
PipelineBuilder* CreatePipelineBuilder();
|
||||
PipelineLayoutBuilder* CreatePipelineLayoutBuilder();
|
||||
QueueBuilder* CreateQueueBuilder();
|
||||
RenderPassBuilder* CreateRenderPassBuilder();
|
||||
SamplerBuilder* CreateSamplerBuilder();
|
||||
ShaderModuleBuilder* CreateShaderModuleBuilder();
|
||||
TextureBuilder* CreateTextureBuilder();
|
||||
|
|
|
@ -32,6 +32,8 @@ namespace backend {
|
|||
class BufferViewBuilder;
|
||||
class CommandBufferBase;
|
||||
class CommandBufferBuilder;
|
||||
class FramebufferBase;
|
||||
class FramebufferBuilder;
|
||||
class InputStateBase;
|
||||
class InputStateBuilder;
|
||||
class PipelineBase;
|
||||
|
@ -40,6 +42,8 @@ namespace backend {
|
|||
class PipelineLayoutBuilder;
|
||||
class QueueBase;
|
||||
class QueueBuilder;
|
||||
class RenderPassBase;
|
||||
class RenderPassBuilder;
|
||||
class SamplerBase;
|
||||
class SamplerBuilder;
|
||||
class ShaderModuleBase;
|
||||
|
@ -64,6 +68,7 @@ namespace backend {
|
|||
static constexpr uint32_t kMaxVertexAttributes = 16u;
|
||||
static constexpr uint32_t kMaxVertexInputs = 16u;
|
||||
static constexpr uint32_t kNumStages = 3;
|
||||
static constexpr uint32_t kMaxColorAttachments = 4u;
|
||||
|
||||
enum PushConstantType : uint8_t;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
// Copyright 2017 The NXT Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "Framebuffer.h"
|
||||
|
||||
#include "Buffer.h"
|
||||
#include "Device.h"
|
||||
#include "RenderPass.h"
|
||||
#include "Texture.h"
|
||||
|
||||
namespace backend {
|
||||
|
||||
// Framebuffer
|
||||
|
||||
FramebufferBase::FramebufferBase(FramebufferBuilder* builder)
|
||||
: renderPass(std::move(builder->renderPass)), width(builder->width), height(builder->height), textureViews(std::move(builder->textureViews)) {
|
||||
}
|
||||
|
||||
RenderPassBase* FramebufferBase::GetRenderPass() {
|
||||
return renderPass.Get();
|
||||
}
|
||||
|
||||
TextureViewBase* FramebufferBase::GetTextureView(uint32_t index) {
|
||||
ASSERT(index < textureViews.size());
|
||||
return textureViews[index].Get();
|
||||
}
|
||||
|
||||
// FramebufferBuilder
|
||||
|
||||
enum FramebufferSetProperties {
|
||||
FRAMEBUFFER_PROPERTY_RENDER_PASS = 0x1,
|
||||
FRAMEBUFFER_PROPERTY_DIMENSIONS = 0x2,
|
||||
};
|
||||
|
||||
FramebufferBuilder::FramebufferBuilder(DeviceBase* device)
|
||||
: Builder(device) {
|
||||
}
|
||||
|
||||
FramebufferBase* FramebufferBuilder::GetResultImpl() {
|
||||
constexpr int requiredProperties = FRAMEBUFFER_PROPERTY_RENDER_PASS | FRAMEBUFFER_PROPERTY_DIMENSIONS;
|
||||
if ((propertiesSet & requiredProperties) != requiredProperties) {
|
||||
HandleError("Framebuffer missing properties");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// TODO(kainino@chromium.org): Remove this flag when the
|
||||
// null=backbuffer hack is removed. Then, using null texture views can
|
||||
// be completely disallowed.
|
||||
bool usingBackbufferHack = false;
|
||||
for (auto& textureView : textureViews) {
|
||||
if (!textureView) {
|
||||
if (usingBackbufferHack) {
|
||||
// TODO(kainino@chromium.org) update this too
|
||||
HandleError("Framebuffer has more than one null attachment");
|
||||
return nullptr;
|
||||
}
|
||||
usingBackbufferHack = true;
|
||||
}
|
||||
}
|
||||
|
||||
return device->CreateFramebuffer(this);
|
||||
}
|
||||
|
||||
void FramebufferBuilder::SetRenderPass(RenderPassBase* renderPass) {
|
||||
if ((propertiesSet & FRAMEBUFFER_PROPERTY_RENDER_PASS) != 0) {
|
||||
HandleError("Framebuffer render pass property set multiple times");
|
||||
return;
|
||||
}
|
||||
|
||||
this->renderPass = renderPass;
|
||||
this->textureViews.resize(renderPass->GetAttachmentCount());
|
||||
propertiesSet |= FRAMEBUFFER_PROPERTY_RENDER_PASS;
|
||||
}
|
||||
|
||||
void FramebufferBuilder::SetDimensions(uint32_t width, uint32_t height) {
|
||||
if ((propertiesSet & FRAMEBUFFER_PROPERTY_DIMENSIONS) != 0) {
|
||||
HandleError("Framebuffer dimensions property set multiple times");
|
||||
return;
|
||||
}
|
||||
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
propertiesSet |= FRAMEBUFFER_PROPERTY_DIMENSIONS;
|
||||
}
|
||||
|
||||
void FramebufferBuilder::SetAttachment(uint32_t attachmentSlot, TextureViewBase* textureView) {
|
||||
if ((propertiesSet & FRAMEBUFFER_PROPERTY_RENDER_PASS) == 0) {
|
||||
HandleError("Render pass must be set before framebuffer attachments");
|
||||
return;
|
||||
}
|
||||
if (attachmentSlot >= textureViews.size()) {
|
||||
HandleError("Attachment slot out of bounds");
|
||||
return;
|
||||
}
|
||||
if (textureViews[attachmentSlot]) {
|
||||
HandleError("Framebuffer attachment[i] set multiple times");
|
||||
return;
|
||||
}
|
||||
const auto& attachmentInfo = renderPass->GetAttachmentInfo(attachmentSlot);
|
||||
const auto* texture = textureView->GetTexture();
|
||||
if (attachmentInfo.format != texture->GetFormat()) {
|
||||
HandleError("Texture format does not match attachment format");
|
||||
return;
|
||||
}
|
||||
// TODO(kainino@chromium.org): also check attachment samples, etc.
|
||||
|
||||
textureViews[attachmentSlot] = textureView;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
// Copyright 2017 The NXT Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef BACKEND_COMMON_FRAMEBUFFER_H_
|
||||
#define BACKEND_COMMON_FRAMEBUFFER_H_
|
||||
|
||||
#include "Builder.h"
|
||||
#include "Forward.h"
|
||||
#include "RefCounted.h"
|
||||
|
||||
#include "nxt/nxtcpp.h"
|
||||
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
namespace backend {
|
||||
|
||||
class FramebufferBase : public RefCounted {
|
||||
public:
|
||||
FramebufferBase(FramebufferBuilder* builder);
|
||||
|
||||
RenderPassBase* GetRenderPass();
|
||||
TextureViewBase* GetTextureView(uint32_t index);
|
||||
|
||||
private:
|
||||
Ref<RenderPassBase> renderPass;
|
||||
uint32_t width = 0;
|
||||
uint32_t height = 0;
|
||||
std::vector<Ref<TextureViewBase>> textureViews;
|
||||
};
|
||||
|
||||
class FramebufferBuilder : public Builder<FramebufferBase> {
|
||||
public:
|
||||
FramebufferBuilder(DeviceBase* device);
|
||||
|
||||
bool WasConsumed() const;
|
||||
|
||||
// NXT API
|
||||
FramebufferBase* GetResultImpl() override;
|
||||
void SetRenderPass(RenderPassBase* renderPass);
|
||||
void SetDimensions(uint32_t width, uint32_t height);
|
||||
void SetAttachment(uint32_t attachmentSlot, TextureViewBase* textureView);
|
||||
|
||||
private:
|
||||
friend class FramebufferBase;
|
||||
|
||||
Ref<RenderPassBase> renderPass;
|
||||
uint32_t width = 0;
|
||||
uint32_t height = 0;
|
||||
std::vector<Ref<TextureViewBase>> textureViews;
|
||||
int propertiesSet = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // BACKEND_COMMON_FRAMEBUFFER_H_
|
|
@ -17,6 +17,7 @@
|
|||
#include "Device.h"
|
||||
#include "InputState.h"
|
||||
#include "PipelineLayout.h"
|
||||
#include "RenderPass.h"
|
||||
#include "ShaderModule.h"
|
||||
|
||||
namespace backend {
|
||||
|
@ -25,6 +26,7 @@ namespace backend {
|
|||
|
||||
PipelineBase::PipelineBase(PipelineBuilder* builder)
|
||||
: device(builder->device), stageMask(builder->stageMask), layout(std::move(builder->layout)),
|
||||
renderPass(std::move(builder->renderPass)), subpass(builder->subpass),
|
||||
inputState(std::move(builder->inputState)) {
|
||||
|
||||
if (stageMask != (nxt::ShaderStageBit::Vertex | nxt::ShaderStageBit::Fragment) &&
|
||||
|
@ -33,6 +35,12 @@ namespace backend {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!IsCompute() && !renderPass) {
|
||||
builder->HandleError("Pipeline render pass not set");
|
||||
return;
|
||||
}
|
||||
// TODO(kainino@chromium.org): Need to verify the pipeline against its render subpass.
|
||||
|
||||
auto FillPushConstants = [](const ShaderModuleBase* module, PushConstantInfo* info) {
|
||||
const auto& moduleInfo = module->GetPushConstants();
|
||||
info->mask = moduleInfo.mask;
|
||||
|
@ -79,6 +87,10 @@ namespace backend {
|
|||
return layout.Get();
|
||||
}
|
||||
|
||||
RenderPassBase* PipelineBase::GetRenderPass() {
|
||||
return renderPass.Get();
|
||||
}
|
||||
|
||||
InputStateBase* PipelineBase::GetInputState() {
|
||||
return inputState.Get();
|
||||
}
|
||||
|
@ -114,6 +126,11 @@ namespace backend {
|
|||
this->layout = layout;
|
||||
}
|
||||
|
||||
void PipelineBuilder::SetSubpass(RenderPassBase* renderPass, uint32_t subpass) {
|
||||
this->renderPass = renderPass;
|
||||
this->subpass = subpass;
|
||||
}
|
||||
|
||||
void PipelineBuilder::SetStage(nxt::ShaderStage stage, ShaderModuleBase* module, const char* entryPoint) {
|
||||
if (entryPoint != std::string("main")) {
|
||||
HandleError("Currently the entry point has to be main()");
|
||||
|
|
|
@ -45,6 +45,7 @@ namespace backend {
|
|||
nxt::ShaderStageBit GetStageMask() const;
|
||||
|
||||
PipelineLayoutBase* GetLayout();
|
||||
RenderPassBase* GetRenderPass();
|
||||
InputStateBase* GetInputState();
|
||||
|
||||
// TODO(cwallez@chromium.org): split compute and render pipelines
|
||||
|
@ -55,6 +56,8 @@ namespace backend {
|
|||
|
||||
nxt::ShaderStageBit stageMask;
|
||||
Ref<PipelineLayoutBase> layout;
|
||||
Ref<RenderPassBase> renderPass;
|
||||
uint32_t subpass;
|
||||
PerStage<PushConstantInfo> pushConstants;
|
||||
Ref<InputStateBase> inputState;
|
||||
};
|
||||
|
@ -71,6 +74,7 @@ namespace backend {
|
|||
|
||||
// NXT API
|
||||
void SetLayout(PipelineLayoutBase* layout);
|
||||
void SetSubpass(RenderPassBase* renderPass, uint32_t subpass);
|
||||
void SetStage(nxt::ShaderStage stage, ShaderModuleBase* module, const char* entryPoint);
|
||||
void SetInputState(InputStateBase* inputState);
|
||||
|
||||
|
@ -80,6 +84,8 @@ namespace backend {
|
|||
PipelineBase* GetResultImpl() override;
|
||||
|
||||
Ref<PipelineLayoutBase> layout;
|
||||
Ref<RenderPassBase> renderPass;
|
||||
uint32_t subpass;
|
||||
nxt::ShaderStageBit stageMask;
|
||||
PerStage<StageInfo> stages;
|
||||
Ref<InputStateBase> inputState;
|
||||
|
|
|
@ -0,0 +1,149 @@
|
|||
// Copyright 2017 The NXT Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "RenderPass.h"
|
||||
|
||||
#include "Buffer.h"
|
||||
#include "Device.h"
|
||||
#include "Texture.h"
|
||||
|
||||
namespace backend {
|
||||
|
||||
// RenderPass
|
||||
|
||||
RenderPassBase::RenderPassBase(RenderPassBuilder* builder)
|
||||
: attachments(std::move(builder->attachments)), subpasses(std::move(builder->subpasses)) {
|
||||
}
|
||||
|
||||
uint32_t RenderPassBase::GetAttachmentCount() const {
|
||||
return attachments.size();
|
||||
}
|
||||
|
||||
const RenderPassBase::AttachmentInfo& RenderPassBase::GetAttachmentInfo(uint32_t attachment) const {
|
||||
ASSERT(attachment < attachments.size());
|
||||
return attachments[attachment];
|
||||
}
|
||||
|
||||
uint32_t RenderPassBase::GetSubpassCount() const {
|
||||
return subpasses.size();
|
||||
}
|
||||
|
||||
const RenderPassBase::SubpassInfo& RenderPassBase::GetSubpassInfo(uint32_t subpass) const {
|
||||
ASSERT(subpass < subpasses.size());
|
||||
return subpasses[subpass];
|
||||
}
|
||||
|
||||
bool RenderPassBase::IsCompatibleWith(const RenderPassBase* other) const {
|
||||
// TODO(kainino@chromium.org): This check is overly strict; need actual
|
||||
// compatibility checking (different load and store ops, etc.)
|
||||
return other == this;
|
||||
}
|
||||
|
||||
// RenderPassBuilder
|
||||
|
||||
enum RenderPassSetProperties {
|
||||
RENDERPASS_PROPERTY_ATTACHMENT_COUNT = 0x1,
|
||||
RENDERPASS_PROPERTY_SUBPASS_COUNT = 0x2,
|
||||
};
|
||||
|
||||
RenderPassBuilder::RenderPassBuilder(DeviceBase* device)
|
||||
: Builder(device), subpasses(1) {
|
||||
}
|
||||
|
||||
RenderPassBase* RenderPassBuilder::GetResultImpl() {
|
||||
constexpr int requiredProperties = RENDERPASS_PROPERTY_ATTACHMENT_COUNT | RENDERPASS_PROPERTY_SUBPASS_COUNT;
|
||||
if ((propertiesSet & requiredProperties) != requiredProperties) {
|
||||
HandleError("Render pass missing properties");
|
||||
return nullptr;
|
||||
}
|
||||
for (const auto& prop : attachmentProperties) {
|
||||
if (!prop.all()) {
|
||||
HandleError("A render pass attachment is missing some property");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return device->CreateRenderPass(this);
|
||||
}
|
||||
|
||||
void RenderPassBuilder::SetAttachmentCount(uint32_t attachmentCount) {
|
||||
if ((propertiesSet & RENDERPASS_PROPERTY_ATTACHMENT_COUNT) != 0) {
|
||||
HandleError("Render pass attachment count property set multiple times");
|
||||
return;
|
||||
}
|
||||
|
||||
attachmentProperties.resize(attachmentCount);
|
||||
attachments.resize(attachmentCount);
|
||||
propertiesSet |= RENDERPASS_PROPERTY_ATTACHMENT_COUNT;
|
||||
}
|
||||
|
||||
|
||||
void RenderPassBuilder::AttachmentSetFormat(uint32_t attachmentSlot, nxt::TextureFormat format) {
|
||||
if ((propertiesSet & RENDERPASS_PROPERTY_ATTACHMENT_COUNT) == 0) {
|
||||
HandleError("Render pass attachment count not set yet");
|
||||
return;
|
||||
}
|
||||
if (attachmentSlot > attachments.size()) {
|
||||
HandleError("Render pass attachment index out of bounds");
|
||||
return;
|
||||
}
|
||||
if (attachmentProperties[attachmentSlot][ATTACHMENT_PROPERTY_FORMAT]) {
|
||||
HandleError("Render pass attachment format already set");
|
||||
return;
|
||||
}
|
||||
|
||||
attachments[attachmentSlot].format = format;
|
||||
attachmentProperties[attachmentSlot].set(ATTACHMENT_PROPERTY_FORMAT);
|
||||
}
|
||||
|
||||
void RenderPassBuilder::SetSubpassCount(uint32_t subpassCount) {
|
||||
if ((propertiesSet & RENDERPASS_PROPERTY_SUBPASS_COUNT) != 0) {
|
||||
HandleError("Render pass subpass count property set multiple times");
|
||||
return;
|
||||
}
|
||||
if (subpassCount < 1) {
|
||||
HandleError("Render pass cannot have fewer than one subpass");
|
||||
return;
|
||||
}
|
||||
|
||||
subpasses.resize(subpassCount);
|
||||
propertiesSet |= RENDERPASS_PROPERTY_SUBPASS_COUNT;
|
||||
}
|
||||
|
||||
void RenderPassBuilder::SubpassSetColorAttachment(uint32_t subpass, uint32_t outputAttachmentLocation, uint32_t attachmentSlot) {
|
||||
if ((propertiesSet & RENDERPASS_PROPERTY_SUBPASS_COUNT) == 0) {
|
||||
HandleError("Render pass subpass count not set yet");
|
||||
return;
|
||||
}
|
||||
if (subpass >= subpasses.size()) {
|
||||
HandleError("Subpass index out of bounds");
|
||||
return;
|
||||
}
|
||||
if (outputAttachmentLocation >= kMaxColorAttachments) {
|
||||
HandleError("Subpass output attachment location out of bounds");
|
||||
return;
|
||||
}
|
||||
if (attachmentSlot >= attachments.size()) {
|
||||
HandleError("Subpass attachment slot out of bounds");
|
||||
return;
|
||||
}
|
||||
if (subpasses[subpass].colorAttachmentsSet[outputAttachmentLocation]) {
|
||||
HandleError("Subpass color attachment already set");
|
||||
return;
|
||||
}
|
||||
|
||||
subpasses[subpass].colorAttachmentsSet.set(outputAttachmentLocation);
|
||||
subpasses[subpass].colorAttachments[outputAttachmentLocation] = attachmentSlot;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
// Copyright 2017 The NXT Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef BACKEND_COMMON_RENDERPASS_H_
|
||||
#define BACKEND_COMMON_RENDERPASS_H_
|
||||
|
||||
#include "Builder.h"
|
||||
#include "Forward.h"
|
||||
#include "RefCounted.h"
|
||||
|
||||
#include "nxt/nxtcpp.h"
|
||||
|
||||
#include <array>
|
||||
#include <bitset>
|
||||
#include <vector>
|
||||
|
||||
namespace backend {
|
||||
|
||||
class RenderPassBase : public RefCounted {
|
||||
public:
|
||||
RenderPassBase(RenderPassBuilder* builder);
|
||||
|
||||
struct AttachmentInfo {
|
||||
nxt::TextureFormat format;
|
||||
};
|
||||
|
||||
struct SubpassInfo {
|
||||
std::bitset<kMaxColorAttachments> colorAttachmentsSet;
|
||||
std::array<uint32_t, kMaxColorAttachments> colorAttachments;
|
||||
};
|
||||
|
||||
uint32_t GetAttachmentCount() const;
|
||||
const AttachmentInfo& GetAttachmentInfo(uint32_t attachment) const;
|
||||
uint32_t GetSubpassCount() const;
|
||||
const SubpassInfo& GetSubpassInfo(uint32_t subpass) const;
|
||||
bool IsCompatibleWith(const RenderPassBase* other) const;
|
||||
|
||||
private:
|
||||
std::vector<AttachmentInfo> attachments;
|
||||
std::vector<SubpassInfo> subpasses;
|
||||
};
|
||||
|
||||
class RenderPassBuilder : public Builder<RenderPassBase> {
|
||||
public:
|
||||
RenderPassBuilder(DeviceBase* device);
|
||||
|
||||
bool WasConsumed() const;
|
||||
|
||||
// NXT API
|
||||
RenderPassBase* GetResultImpl() override;
|
||||
void SetAttachmentCount(uint32_t attachmentCount);
|
||||
void AttachmentSetFormat(uint32_t attachmentSlot, nxt::TextureFormat format);
|
||||
void SetSubpassCount(uint32_t subpassCount);
|
||||
void SubpassSetColorAttachment(uint32_t subpass, uint32_t outputAttachmentLocation, uint32_t attachmentSlot);
|
||||
|
||||
private:
|
||||
friend class RenderPassBase;
|
||||
|
||||
enum AttachmentProperty {
|
||||
ATTACHMENT_PROPERTY_FORMAT,
|
||||
ATTACHMENT_PROPERTY_COUNT
|
||||
};
|
||||
|
||||
std::vector<std::bitset<ATTACHMENT_PROPERTY_COUNT>> attachmentProperties;
|
||||
std::vector<RenderPassBase::AttachmentInfo> attachments;
|
||||
std::vector<RenderPassBase::SubpassInfo> subpasses;
|
||||
int propertiesSet = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // BACKEND_COMMON_RENDERPASS_H_
|
|
@ -48,6 +48,11 @@ namespace backend {
|
|||
using BackendType = typename BackendTraits::CommandBufferType;
|
||||
};
|
||||
|
||||
template<typename BackendTraits>
|
||||
struct ToBackendTraits<FramebufferBase, BackendTraits> {
|
||||
using BackendType = typename BackendTraits::FramebufferType;
|
||||
};
|
||||
|
||||
template<typename BackendTraits>
|
||||
struct ToBackendTraits<InputStateBase, BackendTraits> {
|
||||
using BackendType = typename BackendTraits::InputStateType;
|
||||
|
@ -68,6 +73,11 @@ namespace backend {
|
|||
using BackendType = typename BackendTraits::QueueType;
|
||||
};
|
||||
|
||||
template<typename BackendTraits>
|
||||
struct ToBackendTraits<RenderPassBase, BackendTraits> {
|
||||
using BackendType = typename BackendTraits::RenderPassType;
|
||||
};
|
||||
|
||||
template<typename BackendTraits>
|
||||
struct ToBackendTraits<SamplerBase, BackendTraits> {
|
||||
using BackendType = typename BackendTraits::SamplerType;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
const auto& info = currentRenderPass->renderPass->GetSubpassInfo(subpass);
|
||||
auto& framebuffer = currentRenderPass->framebuffer;
|
||||
|
||||
// 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;
|
||||
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?
|
||||
}
|
||||
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) {
|
||||
|
|
|
@ -60,6 +60,17 @@ namespace opengl {
|
|||
|
||||
while(commands.NextCommandId(&type)) {
|
||||
switch (type) {
|
||||
case Command::AdvanceSubpass:
|
||||
{
|
||||
// TODO(kainino@chromium.org): implement
|
||||
}
|
||||
break;
|
||||
|
||||
case Command::BeginRenderPass:
|
||||
{
|
||||
// TODO(kainino@chromium.org): implement
|
||||
}
|
||||
break;
|
||||
|
||||
case Command::CopyBufferToTexture:
|
||||
{
|
||||
|
@ -124,6 +135,12 @@ namespace opengl {
|
|||
}
|
||||
break;
|
||||
|
||||
case Command::EndRenderPass:
|
||||
{
|
||||
// TODO(kainino@chromium.org): implement
|
||||
}
|
||||
break;
|
||||
|
||||
case Command::SetPipeline:
|
||||
{
|
||||
SetPipelineCmd* cmd = commands.NextCommand<SetPipelineCmd>();
|
||||
|
|
|
@ -63,6 +63,9 @@ namespace opengl {
|
|||
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);
|
||||
}
|
||||
|
@ -72,6 +75,9 @@ namespace opengl {
|
|||
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);
|
||||
}
|
||||
|
@ -165,6 +171,12 @@ namespace opengl {
|
|||
return vertexArrayObject;
|
||||
}
|
||||
|
||||
// Framebuffer
|
||||
|
||||
Framebuffer::Framebuffer(Device* device, FramebufferBuilder* builder)
|
||||
: FramebufferBase(builder), device(device) {
|
||||
}
|
||||
|
||||
// Queue
|
||||
|
||||
Queue::Queue(Device* device, QueueBuilder* builder)
|
||||
|
@ -177,5 +189,11 @@ namespace opengl {
|
|||
}
|
||||
}
|
||||
|
||||
// RenderPass
|
||||
|
||||
RenderPass::RenderPass(Device* device, RenderPassBuilder* builder)
|
||||
: RenderPassBase(builder), device(device) {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,8 +21,10 @@
|
|||
#include "common/BindGroup.h"
|
||||
#include "common/BindGroupLayout.h"
|
||||
#include "common/Device.h"
|
||||
#include "common/Framebuffer.h"
|
||||
#include "common/InputState.h"
|
||||
#include "common/Queue.h"
|
||||
#include "common/RenderPass.h"
|
||||
#include "common/ToBackend.h"
|
||||
|
||||
#include "glad/glad.h"
|
||||
|
@ -43,6 +45,8 @@ namespace opengl {
|
|||
class ShaderModule;
|
||||
class Texture;
|
||||
class TextureView;
|
||||
class Framebuffer;
|
||||
class RenderPass;
|
||||
|
||||
struct OpenGLBackendTraits {
|
||||
using BindGroupType = BindGroup;
|
||||
|
@ -58,6 +62,8 @@ namespace opengl {
|
|||
using ShaderModuleType = ShaderModule;
|
||||
using TextureType = Texture;
|
||||
using TextureViewType = TextureView;
|
||||
using FramebufferType = Framebuffer;
|
||||
using RenderPassType = RenderPass;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
|
@ -74,9 +80,11 @@ namespace opengl {
|
|||
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;
|
||||
|
@ -124,6 +132,14 @@ namespace opengl {
|
|||
Device* device;
|
||||
};
|
||||
|
||||
class Framebuffer : public FramebufferBase {
|
||||
public:
|
||||
Framebuffer(Device* device, FramebufferBuilder* builder);
|
||||
|
||||
private:
|
||||
Device* device;
|
||||
};
|
||||
|
||||
class InputState : public InputStateBase {
|
||||
public:
|
||||
InputState(Device* device, InputStateBuilder* builder);
|
||||
|
@ -145,6 +161,14 @@ namespace opengl {
|
|||
Device* device;
|
||||
};
|
||||
|
||||
class RenderPass : public RenderPassBase {
|
||||
public:
|
||||
RenderPass(Device* device, RenderPassBuilder* builder);
|
||||
|
||||
private:
|
||||
Device* device;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue