OpenGL backend: implement render passes (#73)
Probably not the most efficient implementation, but works. Issues: * Doesn't seem to render until the second frame. No clue why, yet. * Hardcoded 640x480 in more places. * Creates new FBOs for every subpass every frame. Should be done at Framebuffer build or CommandBuffer build time.
This commit is contained in:
parent
3df6441a8c
commit
e66fcd8b0e
|
@ -101,6 +101,10 @@ namespace backend {
|
|||
return true;
|
||||
}
|
||||
|
||||
DeviceBase* CommandBufferBase::GetDevice() {
|
||||
return device;
|
||||
}
|
||||
|
||||
void FreeCommands(CommandIterator* commands) {
|
||||
Command type;
|
||||
while(commands->NextCommandId(&type)) {
|
||||
|
|
|
@ -43,6 +43,8 @@ namespace backend {
|
|||
CommandBufferBase(CommandBufferBuilder* builder);
|
||||
bool ValidateResourceUsagesImmediate();
|
||||
|
||||
DeviceBase* GetDevice();
|
||||
|
||||
private:
|
||||
DeviceBase* device;
|
||||
std::set<BufferBase*> buffersTransitioned;
|
||||
|
|
|
@ -67,6 +67,11 @@ namespace opengl {
|
|||
PersistentPipelineState persistentPipelineState;
|
||||
persistentPipelineState.SetDefaultState();
|
||||
|
||||
RenderPass* currentRenderPass = nullptr;
|
||||
Framebuffer* currentFramebuffer = nullptr;
|
||||
uint32_t currentSubpass = 0;
|
||||
GLuint currentFBO = 0;
|
||||
|
||||
while(commands.NextCommandId(&type)) {
|
||||
switch (type) {
|
||||
case Command::BeginComputePass:
|
||||
|
@ -77,15 +82,50 @@ namespace opengl {
|
|||
|
||||
case Command::BeginRenderPass:
|
||||
{
|
||||
commands.NextCommand<BeginRenderPassCmd>();
|
||||
// TODO(kainino@chromium.org): implement
|
||||
auto* cmd = commands.NextCommand<BeginRenderPassCmd>();
|
||||
currentRenderPass = ToBackend(cmd->renderPass.Get());
|
||||
currentFramebuffer = ToBackend(cmd->framebuffer.Get());
|
||||
currentSubpass = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case Command::BeginRenderSubpass:
|
||||
{
|
||||
commands.NextCommand<BeginRenderSubpassCmd>();
|
||||
// TODO(kainino@chromium.org): implement
|
||||
// TODO(kainino@chromium.org): possible future
|
||||
// optimization: create these framebuffers at
|
||||
// Framebuffer build time (or maybe CommandBuffer build
|
||||
// time) so they don't have to be created and destroyed
|
||||
// at draw time.
|
||||
glGenFramebuffers(1, ¤tFBO);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, currentFBO);
|
||||
|
||||
auto* device = ToBackend(GetDevice());
|
||||
const auto& info = currentRenderPass->GetSubpassInfo(currentSubpass);
|
||||
|
||||
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.
|
||||
GLuint texture = 0;
|
||||
if (auto textureView = currentFramebuffer->GetTextureView(attachment)) {
|
||||
texture = ToBackend(textureView->GetTexture())->GetHandle();
|
||||
} else {
|
||||
texture = device->GetCurrentTexture();
|
||||
usingBackbuffer = true;
|
||||
}
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + index,
|
||||
GL_TEXTURE_2D, texture, 0);
|
||||
}
|
||||
// TODO(kainino@chromium.org): load depth attachment from subpass
|
||||
if (usingBackbuffer) {
|
||||
GLuint texture = device->GetCurrentDepthTexture();
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
|
||||
GL_TEXTURE_2D, texture, 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -185,14 +225,15 @@ namespace opengl {
|
|||
case Command::EndRenderPass:
|
||||
{
|
||||
commands.NextCommand<EndRenderPassCmd>();
|
||||
// TODO(kainino@chromium.org): implement
|
||||
}
|
||||
break;
|
||||
|
||||
case Command::EndRenderSubpass:
|
||||
{
|
||||
commands.NextCommand<EndRenderSubpassCmd>();
|
||||
// TODO(kainino@chromium.org): implement
|
||||
glDeleteFramebuffers(1, ¤tFBO);
|
||||
currentFBO = 0;
|
||||
currentSubpass += 1;
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
@ -27,11 +27,9 @@ namespace opengl {
|
|||
nxtProcTable GetNonValidatingProcs();
|
||||
nxtProcTable GetValidatingProcs();
|
||||
|
||||
void HACKCLEAR() {
|
||||
glClearColor(0, 0, 0, 1);
|
||||
glStencilMask(0xff);
|
||||
glClearStencil(0);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
void HACKCLEAR(nxtDevice device) {
|
||||
Device* backendDevice = reinterpret_cast<Device*>(device);
|
||||
backendDevice->HACKCLEAR();
|
||||
}
|
||||
|
||||
void Init(void* (*getProc)(const char*), nxtProcTable* procs, nxtDevice* device) {
|
||||
|
@ -39,11 +37,21 @@ namespace opengl {
|
|||
|
||||
gladLoadGLLoader(reinterpret_cast<GLADloadproc>(getProc));
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
HACKCLEAR();
|
||||
|
||||
*procs = GetValidatingProcs();
|
||||
*device = reinterpret_cast<nxtDevice>(new Device);
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
HACKCLEAR(*device);
|
||||
}
|
||||
|
||||
void InitBackbuffer(nxtDevice device) {
|
||||
Device* backendDevice = reinterpret_cast<Device*>(device);
|
||||
backendDevice->InitBackbuffer();
|
||||
}
|
||||
|
||||
void CommitBackbuffer(nxtDevice device) {
|
||||
Device* backendDevice = reinterpret_cast<Device*>(device);
|
||||
backendDevice->CommitBackbuffer();
|
||||
}
|
||||
|
||||
// Device
|
||||
|
@ -100,6 +108,48 @@ namespace opengl {
|
|||
void Device::TickImpl() {
|
||||
}
|
||||
|
||||
void Device::HACKCLEAR() {
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, backFBO);
|
||||
glClearColor(0, 0, 0, 1);
|
||||
glStencilMask(0xff);
|
||||
glClearStencil(0);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
}
|
||||
|
||||
void Device::InitBackbuffer() {
|
||||
glGenTextures(1, &backTexture);
|
||||
glBindTexture(GL_TEXTURE_2D, backTexture);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 640, 480, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||
|
||||
glGenTextures(1, &backDepthTexture);
|
||||
glBindTexture(GL_TEXTURE_2D, backDepthTexture);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, 640, 480, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, nullptr);
|
||||
|
||||
glGenFramebuffers(1, &backFBO);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, backFBO);
|
||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
GL_TEXTURE_2D, backTexture, 0);
|
||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
|
||||
GL_TEXTURE_2D, backDepthTexture, 0);
|
||||
|
||||
HACKCLEAR();
|
||||
}
|
||||
|
||||
void Device::CommitBackbuffer() {
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, backFBO);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
glBlitFramebuffer(0, 0, 640, 480, 0, 0, 640, 480,
|
||||
GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
}
|
||||
|
||||
GLuint Device::GetCurrentTexture() {
|
||||
return backTexture;
|
||||
}
|
||||
|
||||
GLuint Device::GetCurrentDepthTexture() {
|
||||
return backDepthTexture;
|
||||
}
|
||||
|
||||
// Bind Group
|
||||
|
||||
BindGroup::BindGroup(BindGroupBuilder* builder)
|
||||
|
|
|
@ -98,6 +98,17 @@ namespace opengl {
|
|||
TextureViewBase* CreateTextureView(TextureViewBuilder* builder) override;
|
||||
|
||||
void TickImpl() override;
|
||||
|
||||
void HACKCLEAR();
|
||||
void InitBackbuffer();
|
||||
void CommitBackbuffer();
|
||||
GLuint GetCurrentTexture();
|
||||
GLuint GetCurrentDepthTexture();
|
||||
|
||||
private:
|
||||
GLuint backFBO = 0;
|
||||
GLuint backTexture = 0;
|
||||
GLuint backDepthTexture = 0;
|
||||
};
|
||||
|
||||
class BindGroup : public BindGroupBase {
|
||||
|
|
|
@ -19,7 +19,9 @@
|
|||
namespace backend {
|
||||
namespace opengl {
|
||||
void Init(void* (*getProc)(const char*), nxtProcTable* procs, nxtDevice* device);
|
||||
void HACKCLEAR();
|
||||
void HACKCLEAR(nxtDevice device);
|
||||
void InitBackbuffer(nxtDevice device);
|
||||
void CommitBackbuffer(nxtDevice device);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -42,11 +44,18 @@ namespace utils {
|
|||
void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) override {
|
||||
glfwMakeContextCurrent(window);
|
||||
backend::opengl::Init(reinterpret_cast<void*(*)(const char*)>(glfwGetProcAddress), procs, device);
|
||||
|
||||
backendDevice = *device;
|
||||
backend::opengl::InitBackbuffer(backendDevice);
|
||||
}
|
||||
void SwapBuffers() override {
|
||||
backend::opengl::CommitBackbuffer(backendDevice);
|
||||
glfwSwapBuffers(window);
|
||||
backend::opengl::HACKCLEAR();
|
||||
backend::opengl::HACKCLEAR(backendDevice);
|
||||
}
|
||||
|
||||
private:
|
||||
nxtDevice backendDevice = nullptr;
|
||||
};
|
||||
|
||||
BackendBinding* CreateOpenGLBinding() {
|
||||
|
|
Loading…
Reference in New Issue