Change render passes from multi to single pass.

This as an API change to get closer to the direction in which WebGPU is
headed. The API change in next.json caused a ton of files to be changed
in the same commit to keep things compiling.

API: the Framebuffer and RenderPass objects are now merged in a single
RenderPassInfo that contains the attachments, loadOps and clear values
for a BeginRenderPass command. The concept of subpass is removed.
The RenderPass creation argument to RenderPipelines is replaced by
explicitly setting the format of attachments for RenderPipeline.

Validation: SetPipeline checks are changed to check that the attachments
info set on a RenderPipeline matches the attachments of the render pass.

Backends: Most changes are simplifications of the backends that no
longer require and indirection to query the current subpass out of the
render pass in BeginSubpass, and don't need to get the attachment info
from a RenderPass when creating RenderPipelines. In the Vulkan backend,
a VkRenderPass cache is added to reuse VkRenderPasses between
RenderPassInfos and RenderPipelines.

Tests and examples: they are updated with the simplified API. Tests
specific to the Framebuffer and RenderPass objects were removed and
validation tests for RenderPassInfo were added.

Tested by running CppHelloTriangle on all backends, end2end tests on all
platforms and all examples on the GL backend.
This commit is contained in:
Corentin Wallez
2018-05-02 18:10:13 -04:00
committed by Corentin Wallez
parent 87ec361cc2
commit 6f7749cce9
92 changed files with 1869 additions and 3168 deletions

View File

@@ -254,9 +254,6 @@ namespace backend { namespace opengl {
PushConstantTracker pushConstants;
InputBufferTracker inputBuffers;
RenderPass* currentRenderPass = nullptr;
Framebuffer* currentFramebuffer = nullptr;
uint32_t currentSubpass = 0;
GLuint currentFBO = 0;
while (mCommands.NextCommandId(&type)) {
@@ -268,13 +265,8 @@ namespace backend { namespace opengl {
case Command::BeginRenderPass: {
auto* cmd = mCommands.NextCommand<BeginRenderPassCmd>();
currentRenderPass = ToBackend(cmd->renderPass.Get());
currentFramebuffer = ToBackend(cmd->framebuffer.Get());
currentSubpass = 0;
} break;
RenderPassInfo* info = ToBackend(cmd->info.Get());
case Command::BeginRenderSubpass: {
mCommands.NextCommand<BeginRenderSubpassCmd>();
pushConstants.OnBeginPass();
inputBuffers.OnBeginPass();
@@ -292,8 +284,6 @@ namespace backend { namespace opengl {
glGenFramebuffers(1, &currentFBO);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, currentFBO);
const auto& subpass = currentRenderPass->GetSubpassInfo(currentSubpass);
// Mapping from attachmentSlot to GL framebuffer
// attachment points. Defaults to zero (GL_NONE).
std::array<GLenum, kMaxColorAttachments> drawBuffers = {};
@@ -301,17 +291,15 @@ namespace backend { namespace opengl {
// Construct GL framebuffer
unsigned int attachmentCount = 0;
for (unsigned int location : IterateBitSet(subpass.colorAttachmentsSet)) {
uint32_t attachment = subpass.colorAttachments[location];
auto textureView = currentFramebuffer->GetTextureView(attachment);
for (uint32_t i : IterateBitSet(info->GetColorAttachmentMask())) {
TextureViewBase* textureView = info->GetColorAttachment(i).view.Get();
GLuint texture = ToBackend(textureView->GetTexture())->GetHandle();
// Attach color buffers.
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + location,
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
GL_TEXTURE_2D, texture, 0);
drawBuffers[location] = GL_COLOR_ATTACHMENT0 + location;
attachmentCount = location + 1;
drawBuffers[i] = GL_COLOR_ATTACHMENT0 + i;
attachmentCount = i + 1;
// TODO(kainino@chromium.org): the color clears (later in
// this function) may be undefined for non-normalized integer formats.
@@ -323,10 +311,8 @@ namespace backend { namespace opengl {
}
glDrawBuffers(attachmentCount, drawBuffers.data());
if (subpass.depthStencilAttachmentSet) {
uint32_t attachmentSlot = subpass.depthStencilAttachment;
auto textureView = currentFramebuffer->GetTextureView(attachmentSlot);
if (info->HasDepthStencilAttachment()) {
TextureViewBase* textureView = info->GetDepthStencilAttachment().view.Get();
GLuint texture = ToBackend(textureView->GetTexture())->GetHandle();
nxt::TextureFormat format = textureView->GetTexture()->GetFormat();
@@ -354,52 +340,39 @@ namespace backend { namespace opengl {
// Clear framebuffer attachments as needed
for (unsigned int location : IterateBitSet(subpass.colorAttachmentsSet)) {
uint32_t attachmentSlot = subpass.colorAttachments[location];
const auto& attachmentInfo =
currentRenderPass->GetAttachmentInfo(attachmentSlot);
for (uint32_t i : IterateBitSet(info->GetColorAttachmentMask())) {
const auto& attachmentInfo = info->GetColorAttachment(i);
// Only perform load op on first use
if (attachmentInfo.firstSubpass == currentSubpass) {
// Load op - color
if (attachmentInfo.colorLoadOp == nxt::LoadOp::Clear) {
const auto& clear = currentFramebuffer->GetClearColor(location);
glClearBufferfv(GL_COLOR, location, clear.color);
}
// Load op - color
if (attachmentInfo.loadOp == nxt::LoadOp::Clear) {
glClearBufferfv(GL_COLOR, i, attachmentInfo.clearColor.data());
}
}
if (subpass.depthStencilAttachmentSet) {
uint32_t attachmentSlot = subpass.depthStencilAttachment;
const auto& attachmentInfo =
currentRenderPass->GetAttachmentInfo(attachmentSlot);
if (info->HasDepthStencilAttachment()) {
const auto& attachmentInfo = info->GetDepthStencilAttachment();
nxt::TextureFormat attachmentFormat =
attachmentInfo.view->GetTexture()->GetFormat();
// Only perform load op on first use
if (attachmentInfo.firstSubpass == currentSubpass) {
// Load op - depth/stencil
const auto& clear = currentFramebuffer->GetClearDepthStencil(
subpass.depthStencilAttachment);
bool doDepthClear = TextureFormatHasDepth(attachmentInfo.format) &&
(attachmentInfo.depthLoadOp == nxt::LoadOp::Clear);
bool doStencilClear =
TextureFormatHasStencil(attachmentInfo.format) &&
(attachmentInfo.stencilLoadOp == nxt::LoadOp::Clear);
if (doDepthClear && doStencilClear) {
glClearBufferfi(GL_DEPTH_STENCIL, 0, clear.depth, clear.stencil);
} else if (doDepthClear) {
glClearBufferfv(GL_DEPTH, 0, &clear.depth);
} else if (doStencilClear) {
const GLint clearStencil = clear.stencil;
glClearBufferiv(GL_STENCIL, 0, &clearStencil);
}
// Load op - depth/stencil
bool doDepthClear = TextureFormatHasDepth(attachmentFormat) &&
(attachmentInfo.depthLoadOp == nxt::LoadOp::Clear);
bool doStencilClear = TextureFormatHasStencil(attachmentFormat) &&
(attachmentInfo.stencilLoadOp == nxt::LoadOp::Clear);
if (doDepthClear && doStencilClear) {
glClearBufferfi(GL_DEPTH_STENCIL, 0, attachmentInfo.clearDepth,
attachmentInfo.clearStencil);
} else if (doDepthClear) {
glClearBufferfv(GL_DEPTH, 0, &attachmentInfo.clearDepth);
} else if (doStencilClear) {
const GLint clearStencil = attachmentInfo.clearStencil;
glClearBufferiv(GL_STENCIL, 0, &clearStencil);
}
}
glBlendColor(0, 0, 0, 0);
glViewport(0, 0, currentFramebuffer->GetWidth(),
currentFramebuffer->GetHeight());
glScissor(0, 0, currentFramebuffer->GetWidth(),
currentFramebuffer->GetHeight());
glViewport(0, 0, info->GetWidth(), info->GetHeight());
glScissor(0, 0, info->GetWidth(), info->GetHeight());
} break;
case Command::CopyBufferToBuffer: {
@@ -530,13 +503,8 @@ namespace backend { namespace opengl {
case Command::EndRenderPass: {
mCommands.NextCommand<EndRenderPassCmd>();
} break;
case Command::EndRenderSubpass: {
mCommands.NextCommand<EndRenderSubpassCmd>();
glDeleteFramebuffers(1, &currentFBO);
currentFBO = 0;
currentSubpass += 1;
} break;
case Command::SetComputePipeline: {

View File

@@ -73,17 +73,14 @@ namespace backend { namespace opengl {
InputStateBase* Device::CreateInputState(InputStateBuilder* builder) {
return new InputState(builder);
}
FramebufferBase* Device::CreateFramebuffer(FramebufferBuilder* builder) {
return new Framebuffer(builder);
}
PipelineLayoutBase* Device::CreatePipelineLayout(PipelineLayoutBuilder* builder) {
return new PipelineLayout(builder);
}
QueueBase* Device::CreateQueue(QueueBuilder* builder) {
return new Queue(builder);
}
RenderPassBase* Device::CreateRenderPass(RenderPassBuilder* builder) {
return new RenderPass(builder);
RenderPassInfoBase* Device::CreateRenderPassInfo(RenderPassInfoBuilder* builder) {
return new RenderPassInfo(builder);
}
RenderPipelineBase* Device::CreateRenderPipeline(RenderPipelineBuilder* builder) {
return new RenderPipeline(builder);
@@ -118,11 +115,6 @@ namespace backend { namespace opengl {
: BindGroupLayoutBase(builder) {
}
// Framebuffer
Framebuffer::Framebuffer(FramebufferBuilder* builder) : FramebufferBase(builder) {
}
// Queue
Queue::Queue(QueueBuilder* builder) : QueueBase(builder) {
@@ -134,9 +126,9 @@ namespace backend { namespace opengl {
}
}
// RenderPass
// RenderPassInfo
RenderPass::RenderPass(RenderPassBuilder* builder) : RenderPassBase(builder) {
RenderPassInfo::RenderPassInfo(RenderPassInfoBuilder* builder) : RenderPassInfoBase(builder) {
}
}} // namespace backend::opengl

View File

@@ -23,10 +23,9 @@
#include "backend/Buffer.h"
#include "backend/DepthStencilState.h"
#include "backend/Device.h"
#include "backend/Framebuffer.h"
#include "backend/InputState.h"
#include "backend/Queue.h"
#include "backend/RenderPass.h"
#include "backend/RenderPassInfo.h"
#include "backend/ToBackend.h"
#include "glad/glad.h"
@@ -42,12 +41,11 @@ namespace backend { namespace opengl {
class ComputePipeline;
class DepthStencilState;
class Device;
class Framebuffer;
class InputState;
class PersistentPipelineState;
class PipelineLayout;
class Queue;
class RenderPass;
class RenderPassInfo;
class RenderPipeline;
class Sampler;
class ShaderModule;
@@ -65,11 +63,10 @@ namespace backend { namespace opengl {
using ComputePipelineType = ComputePipeline;
using DepthStencilStateType = DepthStencilState;
using DeviceType = Device;
using FramebufferType = Framebuffer;
using InputStateType = InputState;
using PipelineLayoutType = PipelineLayout;
using QueueType = Queue;
using RenderPassType = RenderPass;
using RenderPassInfoType = RenderPassInfo;
using RenderPipelineType = RenderPipeline;
using SamplerType = Sampler;
using ShaderModuleType = ShaderModule;
@@ -95,10 +92,9 @@ namespace backend { namespace opengl {
ComputePipelineBase* CreateComputePipeline(ComputePipelineBuilder* builder) override;
DepthStencilStateBase* CreateDepthStencilState(DepthStencilStateBuilder* builder) override;
InputStateBase* CreateInputState(InputStateBuilder* builder) override;
FramebufferBase* CreateFramebuffer(FramebufferBuilder* builder) override;
PipelineLayoutBase* CreatePipelineLayout(PipelineLayoutBuilder* builder) override;
QueueBase* CreateQueue(QueueBuilder* builder) override;
RenderPassBase* CreateRenderPass(RenderPassBuilder* builder) override;
RenderPassInfoBase* CreateRenderPassInfo(RenderPassInfoBuilder* builder) override;
RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) override;
SamplerBase* CreateSampler(SamplerBuilder* builder) override;
ShaderModuleBase* CreateShaderModule(ShaderModuleBuilder* builder) override;
@@ -119,11 +115,6 @@ namespace backend { namespace opengl {
BindGroupLayout(BindGroupLayoutBuilder* builder);
};
class Framebuffer : public FramebufferBase {
public:
Framebuffer(FramebufferBuilder* builder);
};
class Queue : public QueueBase {
public:
Queue(QueueBuilder* builder);
@@ -132,9 +123,9 @@ namespace backend { namespace opengl {
void Submit(uint32_t numCommands, CommandBuffer* const* commands);
};
class RenderPass : public RenderPassBase {
class RenderPassInfo : public RenderPassInfoBase {
public:
RenderPass(RenderPassBuilder* builder);
RenderPassInfo(RenderPassInfoBuilder* builder);
};
}} // namespace backend::opengl

View File

@@ -60,10 +60,7 @@ namespace backend { namespace opengl {
auto depthStencilState = ToBackend(GetDepthStencilState());
depthStencilState->ApplyNow(persistentPipelineState);
RenderPass* renderPass = ToBackend(GetRenderPass());
auto& subpassInfo = renderPass->GetSubpassInfo(GetSubPass());
for (uint32_t attachmentSlot : IterateBitSet(subpassInfo.colorAttachmentsSet)) {
for (uint32_t attachmentSlot : IterateBitSet(GetColorAttachmentsMask())) {
ToBackend(GetBlendState(attachmentSlot))->ApplyNow(attachmentSlot);
}
}