Plumb through a parameter for creating framebuffers of different color formats

This commit is contained in:
Henrik Rydgård 2023-02-03 11:40:17 +01:00
parent 6c9963bd26
commit a989b08648
13 changed files with 80 additions and 28 deletions

View File

@ -1325,7 +1325,17 @@ Framebuffer *D3D11DrawContext::CreateFramebuffer(const FramebufferDesc &desc) {
// Texture arrays are supported but we don't have any other use cases yet.
_dbg_assert_(desc.numLayers == 1);
fb->colorFormat = DXGI_FORMAT_R8G8B8A8_UNORM;
DXGI_FORMAT colorFormat;
switch (desc.colorFormat) {
case DataFormat::R8G8B8A8_UNORM:
colorFormat = DXGI_FORMAT_R8G8B8A8_UNORM;
break;
default:
_assert_msg_(false, "Framebuffer format not supported");
return nullptr;
}
fb->colorFormat = colorFormat;
D3D11_TEXTURE2D_DESC descColor{};
descColor.Width = desc.width;
descColor.Height = desc.height;

View File

@ -1264,7 +1264,18 @@ Framebuffer *D3D9Context::CreateFramebuffer(const FramebufferDesc &desc) {
D3D9Framebuffer *fbo = new D3D9Framebuffer(desc.width, desc.height);
fbo->depthstenciltex = nullptr;
HRESULT rtResult = device_->CreateTexture(desc.width, desc.height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &fbo->tex, nullptr);
D3DFORMAT colorFormat;
switch (desc.colorFormat) {
case DataFormat::R8G8B8A8_UNORM:
// We pretend to support this, although in reality we use the reverse format.
colorFormat = D3DFMT_A8R8G8B8;
break;
default:
_assert_msg_(false, "Framebuffer format not supported");
return nullptr;
}
HRESULT rtResult = device_->CreateTexture(desc.width, desc.height, 1, D3DUSAGE_RENDERTARGET, colorFormat, D3DPOOL_DEFAULT, &fbo->tex, nullptr);
if (FAILED(rtResult)) {
ERROR_LOG(G3D, "Failed to create render target");
fbo->Release();

View File

@ -517,7 +517,22 @@ void GLQueueRunner::InitCreateFramebuffer(const GLRInitStep &step) {
// Color texture is same everywhere
glGenFramebuffers(1, &fbo->handle);
initFBOTexture(fbo->color_texture, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, true);
GLint colorInternalFormat;
GLint colorFormat;
GLint colorElementType;
switch (fbo->colorFormat) {
case Draw::DataFormat::R8G8B8A8_UNORM:
colorInternalFormat = GL_RGBA;
colorFormat = GL_RGBA;
colorElementType = GL_UNSIGNED_BYTE;
break;
default:
_assert_msg_(false, "Data format not supported");
return;
}
initFBOTexture(fbo->color_texture, colorInternalFormat, colorFormat, colorElementType, true);
retry_depth:
if (!fbo->z_stencil_) {

View File

@ -106,6 +106,7 @@ void GLDeleter::Perform(GLRenderManager *renderManager, bool skipGLCalls) {
framebuffer->z_stencil_texture.texture = 0;
framebuffer->z_buffer = 0;
framebuffer->stencil_buffer = 0;
framebuffer->colorFormat = Draw::DataFormat::UNDEFINED;
}
delete framebuffer;
}

View File

@ -51,10 +51,9 @@ public:
class GLRFramebuffer {
public:
GLRFramebuffer(const Draw::DeviceCaps &caps, int _width, int _height, bool z_stencil)
GLRFramebuffer(const Draw::DeviceCaps &caps, Draw::DataFormat _colorFormat, int _width, int _height, bool z_stencil)
: color_texture(caps, _width, _height, 1, 1), z_stencil_texture(caps, _width, _height, 1, 1),
width(_width), height(_height), z_stencil_(z_stencil) {
}
colorFormat(_colorFormat), width(_width), height(_height), z_stencil_(z_stencil) {}
~GLRFramebuffer();
@ -65,6 +64,7 @@ public:
GLRTexture z_stencil_texture;
GLuint z_buffer = 0;
GLuint stencil_buffer = 0;
Draw::DataFormat colorFormat;
int width;
int height;
@ -464,9 +464,9 @@ public:
return step.create_shader.shader;
}
GLRFramebuffer *CreateFramebuffer(int width, int height, bool z_stencil) {
GLRFramebuffer *CreateFramebuffer(Draw::DataFormat colorFormat, int width, int height, bool z_stencil) {
GLRInitStep step{ GLRInitStepType::CREATE_FRAMEBUFFER };
step.create_framebuffer.framebuffer = new GLRFramebuffer(caps_, width, height, z_stencil);
step.create_framebuffer.framebuffer = new GLRFramebuffer(caps_, colorFormat, width, height, z_stencil);
initSteps_.push_back(step);
return step.create_framebuffer.framebuffer;
}

View File

@ -1437,7 +1437,7 @@ Framebuffer *OpenGLContext::CreateFramebuffer(const FramebufferDesc &desc) {
// TODO: Support multiview later. (It's our only use case for multi layers).
_dbg_assert_(desc.numLayers == 1);
GLRFramebuffer *framebuffer = renderManager_.CreateFramebuffer(desc.width, desc.height, desc.z_stencil);
GLRFramebuffer *framebuffer = renderManager_.CreateFramebuffer(desc.colorFormat, desc.width, desc.height, desc.z_stencil);
OpenGLFramebuffer *fbo = new OpenGLFramebuffer(&renderManager_, framebuffer);
return fbo;
}

View File

@ -35,12 +35,12 @@ void VKRImage::Delete(VulkanContext *vulkan) {
}
}
VKRFramebuffer::VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VKRRenderPass *compatibleRenderPass, int _width, int _height, int _numLayers, int _multiSampleLevel, bool createDepthStencilBuffer, const char *tag)
VKRFramebuffer::VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VKRRenderPass *compatibleRenderPass, VkFormat colorFormat, int _width, int _height, int _numLayers, int _multiSampleLevel, bool createDepthStencilBuffer, const char *tag)
: vulkan_(vk), tag_(tag), width(_width), height(_height), numLayers(_numLayers) {
_dbg_assert_(tag);
CreateImage(vulkan_, initCmd, color, width, height, numLayers, VK_SAMPLE_COUNT_1_BIT, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true, tag);
CreateImage(vulkan_, initCmd, color, width, height, numLayers, VK_SAMPLE_COUNT_1_BIT, colorFormat, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true, tag);
if (createDepthStencilBuffer) {
CreateImage(vulkan_, initCmd, depth, width, height, numLayers, VK_SAMPLE_COUNT_1_BIT, vulkan_->GetDeviceInfo().preferredDepthStencilFormat, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, false, tag);
}

View File

@ -58,7 +58,7 @@ struct VKRImage {
class VKRFramebuffer {
public:
VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VKRRenderPass *compatibleRenderPass, int _width, int _height, int _numLayers, int _multiSampleLevel, bool createDepthStencilBuffer, const char *tag);
VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VKRRenderPass *compatibleRenderPass, VkFormat colorFormat, int _width, int _height, int _numLayers, int _multiSampleLevel, bool createDepthStencilBuffer, const char *tag);
~VKRFramebuffer();
VkFramebuffer Get(VKRRenderPass *compatibleRenderPass, RenderPassType rpType);

View File

@ -415,7 +415,8 @@ public:
void CopyFramebufferImage(Framebuffer *src, int level, int x, int y, int z, Framebuffer *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, int channelBits, const char *tag) override;
bool BlitFramebuffer(Framebuffer *src, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dst, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter, const char *tag) override;
bool CopyFramebufferToMemorySync(Framebuffer *src, int channelBits, int x, int y, int w, int h, Draw::DataFormat format, void *pixels, int pixelStride, const char *tag) override;
DataFormat PreferredFramebufferReadbackFormat(Framebuffer *src) override;
DataFormat PreferredColorReadbackFormat(Framebuffer *src) override;
DataFormat PreferredDepthReadbackFormat(Framebuffer *src) override;
// These functions should be self explanatory.
void BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) override;
@ -1602,8 +1603,12 @@ Framebuffer *VKContext::CreateFramebuffer(const FramebufferDesc &desc) {
_assert_(desc.width > 0);
_assert_(desc.height > 0);
_assert_(desc.colorFormat == DataFormat::R8G8B8A8_UNORM || desc.colorFormat == DataFormat::R16_UNORM);
VkFormat colorFormat = DataFormatToVulkan(desc.colorFormat);
VkCommandBuffer cmd = renderManager_.GetInitCmd();
VKRFramebuffer *vkrfb = new VKRFramebuffer(vulkan_, cmd, renderManager_.GetQueueRunner()->GetCompatibleRenderPass(), desc.width, desc.height, desc.numLayers, desc.multiSampleLevel, desc.z_stencil, desc.tag);
VKRFramebuffer *vkrfb = new VKRFramebuffer(vulkan_, cmd, renderManager_.GetQueueRunner()->GetCompatibleRenderPass(), colorFormat, desc.width, desc.height, desc.numLayers, desc.multiSampleLevel, desc.z_stencil, desc.tag);
return new VKFramebuffer(vkrfb, desc.multiSampleLevel);
}
@ -1643,15 +1648,19 @@ bool VKContext::CopyFramebufferToMemorySync(Framebuffer *srcfb, int channelBits,
return renderManager_.CopyFramebufferToMemorySync(src ? src->GetFB() : nullptr, aspectMask, x, y, w, h, format, (uint8_t *)pixels, pixelStride, tag);
}
DataFormat VKContext::PreferredFramebufferReadbackFormat(Framebuffer *src) {
DataFormat VKContext::PreferredColorReadbackFormat(Framebuffer *src) {
if (src) {
return DrawContext::PreferredFramebufferReadbackFormat(src);
return DrawContext::PreferredColorReadbackFormat(src);
}
if (vulkan_->GetSwapchainFormat() == VK_FORMAT_B8G8R8A8_UNORM) {
return Draw::DataFormat::B8G8R8A8_UNORM;
}
return DrawContext::PreferredFramebufferReadbackFormat(src);
return DrawContext::PreferredColorReadbackFormat(src);
}
DataFormat VKContext::PreferredDepthReadbackFormat(Framebuffer *src) {
return Draw::DataFormat::R16_UNORM;
}
void VKContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) {

View File

@ -295,6 +295,7 @@ enum class Event {
constexpr uint32_t MAX_TEXTURE_SLOTS = 3;
struct FramebufferDesc {
DataFormat colorFormat;
int width;
int height;
int depth;
@ -696,9 +697,13 @@ public:
virtual bool CopyFramebufferToMemorySync(Framebuffer *src, int channelBits, int x, int y, int w, int h, Draw::DataFormat format, void *pixels, int pixelStride, const char *tag) {
return false;
}
virtual DataFormat PreferredFramebufferReadbackFormat(Framebuffer *src) {
virtual DataFormat PreferredColorReadbackFormat(Framebuffer *src) {
return DataFormat::R8G8B8A8_UNORM;
}
virtual DataFormat PreferredDepthReadbackFormat(Framebuffer *src) {
// We use a shader to read depth and write color, while scaling.
return DataFormat::R16_UNORM;
}
// These functions should be self explanatory.
// Binding a zero render target means binding the backbuffer.

View File

@ -1689,7 +1689,7 @@ void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, int w,
char tag[128];
size_t len = FormatFramebufferName(vfb, tag, sizeof(tag));
vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, GetFramebufferLayers(), msaaLevel_, true, tag });
vfb->fbo = draw_->CreateFramebuffer({ colorFormat_, vfb->renderWidth, vfb->renderHeight, 1, GetFramebufferLayers(), msaaLevel_, true, tag });
if (Memory::IsVRAMAddress(vfb->fb_address) && vfb->fb_stride != 0) {
NotifyMemInfo(MemBlockFlags::ALLOC, vfb->fb_address, ColorBufferByteSize(vfb), tag, len);
}
@ -2060,7 +2060,7 @@ VirtualFramebuffer *FramebufferManagerCommon::CreateRAMFramebuffer(uint32_t fbAd
char name[64];
snprintf(name, sizeof(name), "%08x_color_RAM", vfb->fb_address);
textureCache_->NotifyFramebuffer(vfb, NOTIFY_FB_CREATED);
vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, GetFramebufferLayers(), 0, true, name });
vfb->fbo = draw_->CreateFramebuffer({ colorFormat_, vfb->renderWidth, vfb->renderHeight, 1, GetFramebufferLayers(), 0, true, name });
vfbs_.push_back(vfb);
u32 byteSize = ColorBufferByteSize(vfb);
@ -2112,8 +2112,7 @@ VirtualFramebuffer *FramebufferManagerCommon::FindDownloadTempBuffer(VirtualFram
char name[64];
snprintf(name, sizeof(name), "download_temp");
// TODO: We don't have a way to create a depth-only framebuffer yet.
// Also, at least on Vulkan we always create both depth and color, need to rework how we handle renderpasses.
nvfb->fbo = draw_->CreateFramebuffer({ nvfb->bufferWidth, nvfb->bufferHeight, 1, 1, 0, channel == RASTER_DEPTH ? true : false, name });
nvfb->fbo = draw_->CreateFramebuffer({ colorFormat_, nvfb->bufferWidth, nvfb->bufferHeight, 1, 1, 0, channel == RASTER_DEPTH ? true : false, name });
if (!nvfb->fbo) {
ERROR_LOG(FRAMEBUF, "Error creating FBO! %d x %d", nvfb->renderWidth, nvfb->renderHeight);
delete nvfb;
@ -2496,7 +2495,7 @@ static const char *TempFBOReasonToString(TempFBO reason) {
}
Draw::Framebuffer *FramebufferManagerCommon::GetTempFBO(TempFBO reason, u16 w, u16 h) {
u64 key = ((u64)reason << 48) | ((u32)w << 16) | h;
u64 key = ((u64)reason << 48) | ((u64)w << 16) | h;
auto it = tempFBOs_.find(key);
if (it != tempFBOs_.end()) {
it->second.last_frame_used = gpuStats.numFlips;
@ -2507,7 +2506,7 @@ Draw::Framebuffer *FramebufferManagerCommon::GetTempFBO(TempFBO reason, u16 w, u
char name[128];
snprintf(name, sizeof(name), "tempfbo_%s_%dx%d", TempFBOReasonToString(reason), w / renderScaleFactor_, h / renderScaleFactor_);
Draw::Framebuffer *fbo = draw_->CreateFramebuffer({ w, h, 1, GetFramebufferLayers(), 0, z_stencil, name });
Draw::Framebuffer *fbo = draw_->CreateFramebuffer({ colorFormat_, w, h, 1, GetFramebufferLayers(), 0, z_stencil, name });
if (!fbo) {
return nullptr;
}
@ -2699,7 +2698,7 @@ bool FramebufferManagerCommon::GetStencilbuffer(u32 fb_address, int fb_stride, G
bool FramebufferManagerCommon::GetOutputFramebuffer(GPUDebugBuffer &buffer) {
int w, h;
draw_->GetFramebufferDimensions(nullptr, &w, &h);
Draw::DataFormat fmt = draw_->PreferredFramebufferReadbackFormat(nullptr);
Draw::DataFormat fmt = draw_->PreferredColorReadbackFormat(nullptr);
// Ignore preferred formats other than BGRA.
if (fmt != Draw::DataFormat::B8G8R8A8_UNORM)
fmt = Draw::DataFormat::R8G8B8A8_UNORM;
@ -3202,7 +3201,7 @@ VirtualFramebuffer *FramebufferManagerCommon::ResolveFramebufferColorToFormat(Vi
char tag[128];
FormatFramebufferName(vfb, tag, sizeof(tag));
vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, GetFramebufferLayers(), 0, true, tag });
vfb->fbo = draw_->CreateFramebuffer({ colorFormat_, vfb->renderWidth, vfb->renderHeight, 1, GetFramebufferLayers(), 0, true, tag });
vfbs_.push_back(vfb);
}

View File

@ -605,4 +605,6 @@ protected:
Draw2D draw2D_;
// The fragment shaders are "owned" by the pipelines since they're 1:1.
const Draw::DataFormat colorFormat_ = Draw::DataFormat::R8G8B8A8_UNORM;
};

View File

@ -278,7 +278,7 @@ bool PresentationCommon::UpdatePostShader() {
previousIndex_ = 0;
for (int i = 0; i < FRAMES; ++i) {
previousFramebuffers_[i] = draw_->CreateFramebuffer({ w, h, 1, 1, 0, false, "inter_presentation" });
previousFramebuffers_[i] = draw_->CreateFramebuffer({ Draw::DataFormat::R8G8B8A8_UNORM, w, h, 1, 1, 0, false, "inter_presentation" });
if (!previousFramebuffers_[i]) {
DestroyPostShader();
return false;
@ -394,7 +394,7 @@ bool PresentationCommon::AllocateFramebuffer(int w, int h) {
}
// No depth/stencil for post processing
Draw::Framebuffer *fbo = draw_->CreateFramebuffer({ w, h, 1, 1, 0, false, "presentation" });
Draw::Framebuffer *fbo = draw_->CreateFramebuffer({ Draw::DataFormat::R8G8B8A8_UNORM, w, h, 1, 1, 0, false, "presentation" });
if (!fbo) {
return false;
}