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:
Kai Ninomiya
2017-05-16 14:04:22 -07:00
committed by Kai Ninomiya
parent ca309db58a
commit 68df8b0a3a
34 changed files with 1305 additions and 54 deletions

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;
};

View File

@@ -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);
}

View File

@@ -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();

View File

@@ -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;
}

View File

@@ -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;
}
}

View File

@@ -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_

View File

@@ -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()");

View File

@@ -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;

View File

@@ -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;
}
}

View File

@@ -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_

View File

@@ -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;

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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>();

View File

@@ -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) {
}
}
}

View File

@@ -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;
};
}
}