2017-05-16 21:04:22 +00:00
|
|
|
// 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.
|
|
|
|
|
2017-07-06 18:41:13 +00:00
|
|
|
#include "backend/Framebuffer.h"
|
2017-05-16 21:04:22 +00:00
|
|
|
|
2017-07-06 18:41:13 +00:00
|
|
|
#include "backend/Buffer.h"
|
|
|
|
#include "backend/Device.h"
|
|
|
|
#include "backend/RenderPass.h"
|
|
|
|
#include "backend/Texture.h"
|
2017-07-10 17:46:05 +00:00
|
|
|
#include "common/Assert.h"
|
2017-05-16 21:04:22 +00:00
|
|
|
|
|
|
|
namespace backend {
|
|
|
|
|
|
|
|
// Framebuffer
|
|
|
|
|
|
|
|
FramebufferBase::FramebufferBase(FramebufferBuilder* builder)
|
2017-08-11 21:36:20 +00:00
|
|
|
: device(builder->device), renderPass(std::move(builder->renderPass)),
|
|
|
|
width(builder->width), height(builder->height), textureViews(std::move(builder->textureViews)),
|
|
|
|
clearColors(textureViews.size()), clearDepthStencils(textureViews.size()) {
|
|
|
|
}
|
|
|
|
|
|
|
|
DeviceBase* FramebufferBase::GetDevice() {
|
|
|
|
return device;
|
2017-05-16 21:04:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
RenderPassBase* FramebufferBase::GetRenderPass() {
|
|
|
|
return renderPass.Get();
|
|
|
|
}
|
|
|
|
|
2017-08-11 21:36:20 +00:00
|
|
|
TextureViewBase* FramebufferBase::GetTextureView(uint32_t attachmentSlot) {
|
|
|
|
ASSERT(attachmentSlot < textureViews.size());
|
|
|
|
return textureViews[attachmentSlot].Get();
|
|
|
|
}
|
|
|
|
|
|
|
|
FramebufferBase::ClearColor FramebufferBase::GetClearColor(uint32_t attachmentSlot) {
|
|
|
|
ASSERT(attachmentSlot < clearColors.size());
|
|
|
|
return clearColors[attachmentSlot];
|
|
|
|
}
|
|
|
|
|
|
|
|
FramebufferBase::ClearDepthStencil FramebufferBase::GetClearDepthStencil(uint32_t attachmentSlot) {
|
|
|
|
ASSERT(attachmentSlot < clearDepthStencils.size());
|
|
|
|
return clearDepthStencils[attachmentSlot];
|
2017-05-16 21:04:22 +00:00
|
|
|
}
|
|
|
|
|
2017-06-05 21:22:48 +00:00
|
|
|
uint32_t FramebufferBase::GetWidth() const {
|
|
|
|
return width;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t FramebufferBase::GetHeight() const {
|
|
|
|
return height;
|
|
|
|
}
|
|
|
|
|
2017-08-11 21:36:20 +00:00
|
|
|
void FramebufferBase::AttachmentSetClearColor(uint32_t attachmentSlot, float clearR, float clearG, float clearB, float clearA) {
|
|
|
|
if (attachmentSlot >= renderPass->GetAttachmentCount()) {
|
|
|
|
device->HandleError("Framebuffer attachment out of bounds");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ASSERT(attachmentSlot < clearColors.size());
|
|
|
|
auto& c = clearColors[attachmentSlot];
|
|
|
|
c.color[0] = clearR;
|
|
|
|
c.color[1] = clearG;
|
|
|
|
c.color[2] = clearB;
|
|
|
|
c.color[3] = clearA;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FramebufferBase::AttachmentSetClearDepthStencil(uint32_t attachmentSlot, float clearDepth, uint32_t clearStencil) {
|
|
|
|
if (attachmentSlot >= renderPass->GetAttachmentCount()) {
|
|
|
|
device->HandleError("Framebuffer attachment out of bounds");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ASSERT(attachmentSlot < clearDepthStencils.size());
|
|
|
|
auto& c = clearDepthStencils[attachmentSlot];
|
|
|
|
c.depth = clearDepth;
|
|
|
|
c.stencil = clearStencil;
|
|
|
|
}
|
|
|
|
|
2017-05-16 21:04:22 +00:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto& textureView : textureViews) {
|
|
|
|
if (!textureView) {
|
2017-08-14 23:32:26 +00:00
|
|
|
HandleError("Framebuffer attachment not set");
|
|
|
|
return nullptr;
|
2017-07-12 17:15:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO(cwallez@chromium.org): Adjust for the mip-level once that is supported.
|
|
|
|
if (textureView->GetTexture()->GetWidth() != width ||
|
|
|
|
textureView->GetTexture()->GetHeight() != height) {
|
|
|
|
HandleError("Framebuffer size doesn't match attachment size");
|
|
|
|
return nullptr;
|
2017-05-16 21:04:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2017-06-09 01:25:14 +00:00
|
|
|
// TODO(kainino@chromium.org): null checks should not be necessary
|
|
|
|
if (renderPass == nullptr) {
|
|
|
|
HandleError("Render pass invalid");
|
|
|
|
return;
|
|
|
|
}
|
2017-05-16 21:04:22 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|