mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-02-13 15:59:23 +01:00
Merge pull request #6315 from stenzek/abstract-framebuffers
Abstract Framebuffers
This commit is contained in:
commit
24a46dc6af
@ -43,42 +43,84 @@ DXGI_FORMAT GetDXGIFormatForHostFormat(AbstractTextureFormat format)
|
||||
return DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
case AbstractTextureFormat::BGRA8:
|
||||
return DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
case AbstractTextureFormat::R16:
|
||||
return DXGI_FORMAT_R16_UNORM;
|
||||
case AbstractTextureFormat::R32F:
|
||||
return DXGI_FORMAT_R32_FLOAT;
|
||||
case AbstractTextureFormat::D16:
|
||||
return DXGI_FORMAT_R16_TYPELESS;
|
||||
case AbstractTextureFormat::D32F:
|
||||
return DXGI_FORMAT_R32_TYPELESS;
|
||||
case AbstractTextureFormat::D32F_S8:
|
||||
return DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS;
|
||||
default:
|
||||
PanicAlert("Unhandled texture format.");
|
||||
return DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
}
|
||||
}
|
||||
DXGI_FORMAT GetSRVFormatForHostFormat(AbstractTextureFormat format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case AbstractTextureFormat::D16:
|
||||
return DXGI_FORMAT_R16_UNORM;
|
||||
case AbstractTextureFormat::D32F:
|
||||
return DXGI_FORMAT_R32_FLOAT;
|
||||
case AbstractTextureFormat::D32F_S8:
|
||||
return DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS;
|
||||
default:
|
||||
return GetDXGIFormatForHostFormat(format);
|
||||
}
|
||||
}
|
||||
DXGI_FORMAT GetDSVFormatForHostFormat(AbstractTextureFormat format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case AbstractTextureFormat::D16:
|
||||
return DXGI_FORMAT_D16_UNORM;
|
||||
case AbstractTextureFormat::D32F:
|
||||
return DXGI_FORMAT_D32_FLOAT;
|
||||
case AbstractTextureFormat::D32F_S8:
|
||||
return DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
|
||||
default:
|
||||
return GetDXGIFormatForHostFormat(format);
|
||||
}
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
DXTexture::DXTexture(const TextureConfig& tex_config) : AbstractTexture(tex_config)
|
||||
{
|
||||
DXGI_FORMAT dxgi_format = GetDXGIFormatForHostFormat(m_config.format);
|
||||
if (m_config.rendertarget)
|
||||
DXGI_FORMAT tex_format = GetDXGIFormatForHostFormat(m_config.format);
|
||||
DXGI_FORMAT srv_format = GetSRVFormatForHostFormat(m_config.format);
|
||||
DXGI_FORMAT rtv_format = DXGI_FORMAT_UNKNOWN;
|
||||
DXGI_FORMAT dsv_format = DXGI_FORMAT_UNKNOWN;
|
||||
UINT bind_flags = D3D11_BIND_SHADER_RESOURCE;
|
||||
if (tex_config.rendertarget)
|
||||
{
|
||||
m_texture = D3DTexture2D::Create(
|
||||
m_config.width, m_config.height,
|
||||
(D3D11_BIND_FLAG)((int)D3D11_BIND_RENDER_TARGET | (int)D3D11_BIND_SHADER_RESOURCE),
|
||||
D3D11_USAGE_DEFAULT, dxgi_format, 1, m_config.layers);
|
||||
if (IsDepthFormat(tex_config.format))
|
||||
{
|
||||
bind_flags |= D3D11_BIND_DEPTH_STENCIL;
|
||||
dsv_format = GetDSVFormatForHostFormat(m_config.format);
|
||||
}
|
||||
else
|
||||
{
|
||||
bind_flags |= D3D11_BIND_RENDER_TARGET;
|
||||
rtv_format = tex_format;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const D3D11_TEXTURE2D_DESC texdesc =
|
||||
CD3D11_TEXTURE2D_DESC(dxgi_format, m_config.width, m_config.height, 1, m_config.levels,
|
||||
D3D11_BIND_SHADER_RESOURCE, D3D11_USAGE_DEFAULT, 0);
|
||||
|
||||
ID3D11Texture2D* pTexture;
|
||||
const HRESULT hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &pTexture);
|
||||
CHECK(SUCCEEDED(hr), "Create texture of the TextureCache");
|
||||
CD3D11_TEXTURE2D_DESC texdesc(tex_format, tex_config.width, tex_config.height, tex_config.layers,
|
||||
tex_config.levels, bind_flags, D3D11_USAGE_DEFAULT, 0,
|
||||
tex_config.samples, 0, 0);
|
||||
|
||||
m_texture = new D3DTexture2D(pTexture, D3D11_BIND_SHADER_RESOURCE);
|
||||
ID3D11Texture2D* pTexture;
|
||||
HRESULT hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &pTexture);
|
||||
CHECK(SUCCEEDED(hr), "Create backing DXTexture");
|
||||
|
||||
// TODO: better debug names
|
||||
D3D::SetDebugObjectName(m_texture->GetTex(), "a texture of the TextureCache");
|
||||
D3D::SetDebugObjectName(m_texture->GetSRV(),
|
||||
"shader resource view of a texture of the TextureCache");
|
||||
m_texture = new D3DTexture2D(pTexture, static_cast<D3D11_BIND_FLAG>(bind_flags), srv_format,
|
||||
dsv_format, rtv_format, tex_config.samples > 1);
|
||||
|
||||
SAFE_RELEASE(pTexture);
|
||||
}
|
||||
SAFE_RELEASE(pTexture);
|
||||
}
|
||||
|
||||
DXTexture::~DXTexture()
|
||||
@ -144,10 +186,25 @@ void DXTexture::ScaleRectangleFromTexture(const AbstractTexture* source,
|
||||
VertexShaderCache::GetSimpleInputLayout(),
|
||||
GeometryShaderCache::GetCopyGeometryShader(), 1.0, 0);
|
||||
|
||||
FramebufferManager::BindEFBRenderTarget();
|
||||
g_renderer->RestoreAPIState();
|
||||
}
|
||||
|
||||
void DXTexture::ResolveFromTexture(const AbstractTexture* src, const MathUtil::Rectangle<int>& rect,
|
||||
u32 layer, u32 level)
|
||||
{
|
||||
const DXTexture* srcentry = static_cast<const DXTexture*>(src);
|
||||
_dbg_assert_(VIDEO, m_config.samples > 1 && m_config.width == srcentry->m_config.width &&
|
||||
m_config.height == srcentry->m_config.height && m_config.samples == 1);
|
||||
_dbg_assert_(VIDEO,
|
||||
rect.left + rect.GetWidth() <= static_cast<int>(srcentry->m_config.width) &&
|
||||
rect.top + rect.GetHeight() <= static_cast<int>(srcentry->m_config.height));
|
||||
|
||||
D3D::context->ResolveSubresource(
|
||||
m_texture->GetTex(), D3D11CalcSubresource(level, layer, m_config.levels),
|
||||
srcentry->m_texture->GetTex(), D3D11CalcSubresource(level, layer, srcentry->m_config.levels),
|
||||
GetDXGIFormatForHostFormat(m_config.format));
|
||||
}
|
||||
|
||||
void DXTexture::Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer,
|
||||
size_t buffer_size)
|
||||
{
|
||||
@ -287,4 +344,88 @@ void DXStagingTexture::Flush()
|
||||
m_needs_flush = false;
|
||||
}
|
||||
|
||||
DXFramebuffer::DXFramebuffer(AbstractTextureFormat color_format, AbstractTextureFormat depth_format,
|
||||
u32 width, u32 height, u32 layers, u32 samples,
|
||||
ID3D11RenderTargetView* rtv, ID3D11DepthStencilView* dsv)
|
||||
: AbstractFramebuffer(color_format, depth_format, width, height, layers, samples), m_rtv(rtv),
|
||||
m_dsv(dsv)
|
||||
{
|
||||
}
|
||||
|
||||
DXFramebuffer::~DXFramebuffer()
|
||||
{
|
||||
if (m_rtv)
|
||||
m_rtv->Release();
|
||||
if (m_dsv)
|
||||
m_dsv->Release();
|
||||
}
|
||||
|
||||
std::unique_ptr<DXFramebuffer> DXFramebuffer::Create(const DXTexture* color_attachment,
|
||||
const DXTexture* depth_attachment)
|
||||
{
|
||||
if (!ValidateConfig(color_attachment, depth_attachment))
|
||||
return nullptr;
|
||||
|
||||
const AbstractTextureFormat color_format =
|
||||
color_attachment ? color_attachment->GetFormat() : AbstractTextureFormat::Undefined;
|
||||
const AbstractTextureFormat depth_format =
|
||||
depth_attachment ? depth_attachment->GetFormat() : AbstractTextureFormat::Undefined;
|
||||
const DXTexture* either_attachment = color_attachment ? color_attachment : depth_attachment;
|
||||
const u32 width = either_attachment->GetWidth();
|
||||
const u32 height = either_attachment->GetHeight();
|
||||
const u32 layers = either_attachment->GetLayers();
|
||||
const u32 samples = either_attachment->GetSamples();
|
||||
|
||||
ID3D11RenderTargetView* rtv = nullptr;
|
||||
if (color_attachment)
|
||||
{
|
||||
D3D11_RENDER_TARGET_VIEW_DESC desc;
|
||||
desc.Format = GetDXGIFormatForHostFormat(color_attachment->GetConfig().format);
|
||||
if (color_attachment->GetConfig().IsMultisampled())
|
||||
{
|
||||
desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY;
|
||||
desc.Texture2DMSArray.ArraySize = color_attachment->GetConfig().layers;
|
||||
desc.Texture2DMSArray.FirstArraySlice = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
|
||||
desc.Texture2DArray.ArraySize = color_attachment->GetConfig().layers;
|
||||
desc.Texture2DArray.FirstArraySlice = 0;
|
||||
desc.Texture2DArray.MipSlice = 0;
|
||||
}
|
||||
|
||||
HRESULT hr = D3D::device->CreateRenderTargetView(
|
||||
color_attachment->GetRawTexIdentifier()->GetTex(), &desc, &rtv);
|
||||
CHECK(SUCCEEDED(hr), "Create render target view for framebuffer");
|
||||
}
|
||||
|
||||
ID3D11DepthStencilView* dsv = nullptr;
|
||||
if (depth_attachment)
|
||||
{
|
||||
D3D11_DEPTH_STENCIL_VIEW_DESC desc;
|
||||
desc.Format = GetDXGIFormatForHostFormat(depth_attachment->GetConfig().format);
|
||||
if (depth_attachment->GetConfig().IsMultisampled())
|
||||
{
|
||||
desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY;
|
||||
desc.Texture2DMSArray.ArraySize = depth_attachment->GetConfig().layers;
|
||||
desc.Texture2DMSArray.FirstArraySlice = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY;
|
||||
desc.Texture2DArray.ArraySize = depth_attachment->GetConfig().layers;
|
||||
desc.Texture2DArray.FirstArraySlice = 0;
|
||||
desc.Texture2DArray.MipSlice = 0;
|
||||
}
|
||||
|
||||
HRESULT hr = D3D::device->CreateDepthStencilView(
|
||||
depth_attachment->GetRawTexIdentifier()->GetTex(), &desc, &dsv);
|
||||
CHECK(SUCCEEDED(hr), "Create depth stencil view for framebuffer");
|
||||
}
|
||||
|
||||
return std::make_unique<DXFramebuffer>(color_format, depth_format, width, height, layers, samples,
|
||||
rtv, dsv);
|
||||
}
|
||||
|
||||
} // namespace DX11
|
||||
|
@ -4,8 +4,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
#include "VideoCommon/AbstractFramebuffer.h"
|
||||
#include "VideoCommon/AbstractStagingTexture.h"
|
||||
#include "VideoCommon/AbstractTexture.h"
|
||||
|
||||
@ -26,6 +28,8 @@ public:
|
||||
void ScaleRectangleFromTexture(const AbstractTexture* source,
|
||||
const MathUtil::Rectangle<int>& srcrect,
|
||||
const MathUtil::Rectangle<int>& dstrect) override;
|
||||
void ResolveFromTexture(const AbstractTexture* src, const MathUtil::Rectangle<int>& rect,
|
||||
u32 layer, u32 level) override;
|
||||
void Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer,
|
||||
size_t buffer_size) override;
|
||||
|
||||
@ -61,4 +65,23 @@ private:
|
||||
ID3D11Texture2D* m_tex = nullptr;
|
||||
};
|
||||
|
||||
class DXFramebuffer final : public AbstractFramebuffer
|
||||
{
|
||||
public:
|
||||
DXFramebuffer(AbstractTextureFormat color_format, AbstractTextureFormat depth_format, u32 width,
|
||||
u32 height, u32 layers, u32 samples, ID3D11RenderTargetView* rtv,
|
||||
ID3D11DepthStencilView* dsv);
|
||||
~DXFramebuffer() override;
|
||||
|
||||
ID3D11RenderTargetView* const* GetRTVArray() const { return &m_rtv; }
|
||||
UINT GetNumRTVs() const { return m_rtv ? 1 : 0; }
|
||||
ID3D11DepthStencilView* GetDSV() const { return m_dsv; }
|
||||
static std::unique_ptr<DXFramebuffer> Create(const DXTexture* color_attachment,
|
||||
const DXTexture* depth_attachment);
|
||||
|
||||
protected:
|
||||
ID3D11RenderTargetView* m_rtv;
|
||||
ID3D11DepthStencilView* m_dsv;
|
||||
};
|
||||
|
||||
} // namespace DX11
|
||||
|
@ -87,9 +87,7 @@ D3DTexture2D*& FramebufferManager::GetResolvedEFBDepthTexture()
|
||||
PixelShaderCache::GetDepthResolveProgram(), VertexShaderCache::GetSimpleVertexShader(),
|
||||
VertexShaderCache::GetSimpleInputLayout(), GeometryShaderCache::GetCopyGeometryShader());
|
||||
|
||||
BindEFBRenderTarget();
|
||||
g_renderer->RestoreAPIState();
|
||||
|
||||
return m_efb.resolved_depth_tex;
|
||||
}
|
||||
else
|
||||
|
@ -43,7 +43,7 @@ PSTextureEncoder::~PSTextureEncoder() = default;
|
||||
void PSTextureEncoder::Init()
|
||||
{
|
||||
// TODO: Move this to a constant somewhere in common.
|
||||
TextureConfig encoding_texture_config(EFB_WIDTH * 4, 1024, 1, 1, AbstractTextureFormat::BGRA8,
|
||||
TextureConfig encoding_texture_config(EFB_WIDTH * 4, 1024, 1, 1, 1, AbstractTextureFormat::BGRA8,
|
||||
true);
|
||||
m_encoding_render_texture = g_renderer->CreateTexture(encoding_texture_config);
|
||||
m_encoding_readback_texture =
|
||||
@ -131,8 +131,6 @@ void PSTextureEncoder::Encode(u8* dst, const EFBCopyParams& params, u32 native_w
|
||||
}
|
||||
}
|
||||
|
||||
// Restore API
|
||||
FramebufferManager::BindEFBRenderTarget();
|
||||
g_renderer->RestoreAPIState();
|
||||
}
|
||||
|
||||
|
@ -90,6 +90,8 @@ Renderer::Renderer(int backbuffer_width, int backbuffer_height)
|
||||
D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)m_target_width, (float)m_target_height);
|
||||
D3D::context->RSSetViewports(1, &vp);
|
||||
FramebufferManager::BindEFBRenderTarget();
|
||||
m_current_framebuffer_width = m_target_width;
|
||||
m_current_framebuffer_height = m_target_height;
|
||||
}
|
||||
|
||||
Renderer::~Renderer()
|
||||
@ -243,6 +245,14 @@ std::unique_ptr<AbstractStagingTexture> Renderer::CreateStagingTexture(StagingTe
|
||||
return DXStagingTexture::Create(type, config);
|
||||
}
|
||||
|
||||
std::unique_ptr<AbstractFramebuffer>
|
||||
Renderer::CreateFramebuffer(const AbstractTexture* color_attachment,
|
||||
const AbstractTexture* depth_attachment)
|
||||
{
|
||||
return DXFramebuffer::Create(static_cast<const DXTexture*>(color_attachment),
|
||||
static_cast<const DXTexture*>(depth_attachment));
|
||||
}
|
||||
|
||||
void Renderer::RenderText(const std::string& text, int left, int top, u32 color)
|
||||
{
|
||||
D3D::DrawTextScaled(static_cast<float>(left + 1), static_cast<float>(top + 1), 20.f, 0.0f,
|
||||
@ -450,7 +460,6 @@ u32 Renderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data)
|
||||
VertexShaderCache::GetSimpleInputLayout());
|
||||
|
||||
// Restore expected game state.
|
||||
FramebufferManager::BindEFBRenderTarget();
|
||||
RestoreAPIState();
|
||||
|
||||
// Copy the pixel from the renderable to cpu-readable buffer.
|
||||
@ -525,7 +534,6 @@ void Renderer::PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num
|
||||
D3D11_VIEWPORT vp =
|
||||
CD3D11_VIEWPORT(0.0f, 0.0f, (float)GetTargetWidth(), (float)GetTargetHeight());
|
||||
D3D::context->RSSetViewports(1, &vp);
|
||||
FramebufferManager::BindEFBRenderTarget(false);
|
||||
}
|
||||
else // if (type == EFBAccessType::PokeZ)
|
||||
{
|
||||
@ -536,7 +544,6 @@ void Renderer::PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num
|
||||
CD3D11_VIEWPORT(0.0f, 0.0f, (float)GetTargetWidth(), (float)GetTargetHeight());
|
||||
|
||||
D3D::context->RSSetViewports(1, &vp);
|
||||
FramebufferManager::BindEFBRenderTarget();
|
||||
}
|
||||
|
||||
D3D::DrawEFBPokeQuads(type, points, num_points);
|
||||
@ -627,10 +634,8 @@ void Renderer::ReinterpretPixelData(unsigned int convtype)
|
||||
GetTargetHeight(), pixel_shader, VertexShaderCache::GetSimpleVertexShader(),
|
||||
VertexShaderCache::GetSimpleInputLayout(), GeometryShaderCache::GetCopyGeometryShader());
|
||||
|
||||
RestoreAPIState();
|
||||
|
||||
FramebufferManager::SwapReinterpretTexture();
|
||||
FramebufferManager::BindEFBRenderTarget();
|
||||
RestoreAPIState();
|
||||
}
|
||||
|
||||
void Renderer::SetBlendingState(const BlendingState& state)
|
||||
@ -653,6 +658,9 @@ void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region
|
||||
static constexpr std::array<float, 4> clear_color{{0.f, 0.f, 0.f, 1.f}};
|
||||
D3D::context->OMSetRenderTargets(1, &D3D::GetBackBuffer()->GetRTV(), nullptr);
|
||||
D3D::context->ClearRenderTargetView(D3D::GetBackBuffer()->GetRTV(), clear_color.data());
|
||||
m_current_framebuffer = nullptr;
|
||||
m_current_framebuffer_width = m_backbuffer_width;
|
||||
m_current_framebuffer_height = m_backbuffer_height;
|
||||
|
||||
// activate linear filtering for the buffer copies
|
||||
D3D::SetLinearCopySampler();
|
||||
@ -707,7 +715,6 @@ void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region
|
||||
|
||||
// begin next frame
|
||||
RestoreAPIState();
|
||||
FramebufferManager::BindEFBRenderTarget();
|
||||
}
|
||||
|
||||
void Renderer::CheckForSurfaceChange()
|
||||
@ -769,6 +776,10 @@ void Renderer::ResetAPIState()
|
||||
void Renderer::RestoreAPIState()
|
||||
{
|
||||
// Gets us back into a more game-like state.
|
||||
m_current_framebuffer = nullptr;
|
||||
m_current_framebuffer_width = m_target_width;
|
||||
m_current_framebuffer_height = m_target_height;
|
||||
FramebufferManager::BindEFBRenderTarget();
|
||||
BPFunctions::SetViewport();
|
||||
BPFunctions::SetScissor();
|
||||
}
|
||||
@ -797,6 +808,36 @@ void Renderer::RestoreState()
|
||||
{
|
||||
}
|
||||
|
||||
void Renderer::SetFramebuffer(const AbstractFramebuffer* framebuffer)
|
||||
{
|
||||
const DXFramebuffer* fb = static_cast<const DXFramebuffer*>(framebuffer);
|
||||
D3D::context->OMSetRenderTargets(fb->GetNumRTVs(), fb->GetRTVArray(), fb->GetDSV());
|
||||
m_current_framebuffer = fb;
|
||||
m_current_framebuffer_width = fb->GetWidth();
|
||||
m_current_framebuffer_height = fb->GetHeight();
|
||||
}
|
||||
|
||||
void Renderer::SetAndDiscardFramebuffer(const AbstractFramebuffer* framebuffer)
|
||||
{
|
||||
SetFramebuffer(framebuffer);
|
||||
}
|
||||
|
||||
void Renderer::SetAndClearFramebuffer(const AbstractFramebuffer* framebuffer,
|
||||
const ClearColor& color_value, float depth_value)
|
||||
{
|
||||
SetFramebuffer(framebuffer);
|
||||
if (framebuffer->GetColorFormat() != AbstractTextureFormat::Undefined)
|
||||
{
|
||||
D3D::context->ClearRenderTargetView(
|
||||
static_cast<const DXFramebuffer*>(framebuffer)->GetRTVArray()[0], color_value.data());
|
||||
}
|
||||
if (framebuffer->GetDepthFormat() != AbstractTextureFormat::Undefined)
|
||||
{
|
||||
D3D::context->ClearDepthStencilView(static_cast<const DXFramebuffer*>(framebuffer)->GetDSV(),
|
||||
D3D11_CLEAR_DEPTH, depth_value, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::SetRasterizationState(const RasterizationState& state)
|
||||
{
|
||||
m_gx_state.raster.hex = state.hex;
|
||||
|
@ -31,8 +31,16 @@ public:
|
||||
std::unique_ptr<AbstractShader> CreateShaderFromBinary(ShaderStage stage, const void* data,
|
||||
size_t length) override;
|
||||
std::unique_ptr<AbstractPipeline> CreatePipeline(const AbstractPipelineConfig& config) override;
|
||||
std::unique_ptr<AbstractFramebuffer>
|
||||
CreateFramebuffer(const AbstractTexture* color_attachment,
|
||||
const AbstractTexture* depth_attachment) override;
|
||||
|
||||
void SetPipeline(const AbstractPipeline* pipeline) override;
|
||||
void SetFramebuffer(const AbstractFramebuffer* framebuffer) override;
|
||||
void SetAndDiscardFramebuffer(const AbstractFramebuffer* framebuffer) override;
|
||||
void SetAndClearFramebuffer(const AbstractFramebuffer* framebuffer,
|
||||
const ClearColor& color_value = {},
|
||||
float depth_value = 0.0f) override;
|
||||
void SetBlendingState(const BlendingState& state) override;
|
||||
void SetScissorRect(const MathUtil::Rectangle<int>& rc) override;
|
||||
void SetRasterizationState(const RasterizationState& state) override;
|
||||
|
@ -160,7 +160,6 @@ void TextureCache::ConvertTexture(TCacheEntry* destination, TCacheEntry* source,
|
||||
VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(),
|
||||
GeometryShaderCache::GetCopyGeometryShader());
|
||||
|
||||
FramebufferManager::BindEFBRenderTarget();
|
||||
g_renderer->RestoreAPIState();
|
||||
}
|
||||
|
||||
@ -275,7 +274,6 @@ void TextureCache::CopyEFBToCacheEntry(TCacheEntry* entry, bool is_depth_copy,
|
||||
pixel_shader, VertexShaderCache::GetSimpleVertexShader(),
|
||||
VertexShaderCache::GetSimpleInputLayout(), GeometryShaderCache::GetCopyGeometryShader());
|
||||
|
||||
FramebufferManager::BindEFBRenderTarget();
|
||||
g_renderer->RestoreAPIState();
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,10 @@ void NullTexture::ScaleRectangleFromTexture(const AbstractTexture* source,
|
||||
const MathUtil::Rectangle<int>& dstrect)
|
||||
{
|
||||
}
|
||||
void NullTexture::ResolveFromTexture(const AbstractTexture* src,
|
||||
const MathUtil::Rectangle<int>& rect, u32 layer, u32 level)
|
||||
{
|
||||
}
|
||||
|
||||
void NullTexture::Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer,
|
||||
size_t buffer_size)
|
||||
@ -66,4 +70,31 @@ void NullStagingTexture::Flush()
|
||||
m_needs_flush = false;
|
||||
}
|
||||
|
||||
NullFramebuffer::NullFramebuffer(AbstractTextureFormat color_format,
|
||||
AbstractTextureFormat depth_format, u32 width, u32 height,
|
||||
u32 layers, u32 samples)
|
||||
: AbstractFramebuffer(color_format, depth_format, width, height, layers, samples)
|
||||
{
|
||||
}
|
||||
|
||||
std::unique_ptr<NullFramebuffer> NullFramebuffer::Create(const NullTexture* color_attachment,
|
||||
const NullTexture* depth_attachment)
|
||||
{
|
||||
if (!ValidateConfig(color_attachment, depth_attachment))
|
||||
return nullptr;
|
||||
|
||||
const AbstractTextureFormat color_format =
|
||||
color_attachment ? color_attachment->GetFormat() : AbstractTextureFormat::Undefined;
|
||||
const AbstractTextureFormat depth_format =
|
||||
depth_attachment ? depth_attachment->GetFormat() : AbstractTextureFormat::Undefined;
|
||||
const NullTexture* either_attachment = color_attachment ? color_attachment : depth_attachment;
|
||||
const u32 width = either_attachment->GetWidth();
|
||||
const u32 height = either_attachment->GetHeight();
|
||||
const u32 layers = either_attachment->GetLayers();
|
||||
const u32 samples = either_attachment->GetSamples();
|
||||
|
||||
return std::make_unique<NullFramebuffer>(color_format, depth_format, width, height, layers,
|
||||
samples);
|
||||
}
|
||||
|
||||
} // namespace Null
|
||||
|
@ -4,10 +4,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
#include "VideoCommon/AbstractFramebuffer.h"
|
||||
#include "VideoCommon/AbstractStagingTexture.h"
|
||||
#include "VideoCommon/AbstractTexture.h"
|
||||
|
||||
@ -26,6 +28,8 @@ public:
|
||||
void ScaleRectangleFromTexture(const AbstractTexture* source,
|
||||
const MathUtil::Rectangle<int>& srcrect,
|
||||
const MathUtil::Rectangle<int>& dstrect) override;
|
||||
void ResolveFromTexture(const AbstractTexture* src, const MathUtil::Rectangle<int>& rect,
|
||||
u32 layer, u32 level) override;
|
||||
void Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer,
|
||||
size_t buffer_size) override;
|
||||
};
|
||||
@ -51,4 +55,15 @@ private:
|
||||
std::vector<u8> m_texture_buf;
|
||||
};
|
||||
|
||||
class NullFramebuffer final : public AbstractFramebuffer
|
||||
{
|
||||
public:
|
||||
explicit NullFramebuffer(AbstractTextureFormat color_format, AbstractTextureFormat depth_format,
|
||||
u32 width, u32 height, u32 layers, u32 samples);
|
||||
~NullFramebuffer() override = default;
|
||||
|
||||
static std::unique_ptr<NullFramebuffer> Create(const NullTexture* color_attachment,
|
||||
const NullTexture* depth_attachment);
|
||||
};
|
||||
|
||||
} // namespace Null
|
||||
|
@ -69,6 +69,14 @@ std::unique_ptr<AbstractPipeline> Renderer::CreatePipeline(const AbstractPipelin
|
||||
return std::make_unique<NullPipeline>();
|
||||
}
|
||||
|
||||
std::unique_ptr<AbstractFramebuffer>
|
||||
Renderer::CreateFramebuffer(const AbstractTexture* color_attachment,
|
||||
const AbstractTexture* depth_attachment)
|
||||
{
|
||||
return NullFramebuffer::Create(static_cast<const NullTexture*>(color_attachment),
|
||||
static_cast<const NullTexture*>(depth_attachment));
|
||||
}
|
||||
|
||||
void Renderer::RenderText(const std::string& text, int left, int top, u32 color)
|
||||
{
|
||||
NOTICE_LOG(VIDEO, "RenderText: %s", text.c_str());
|
||||
|
@ -17,6 +17,9 @@ public:
|
||||
std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config) override;
|
||||
std::unique_ptr<AbstractStagingTexture>
|
||||
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override;
|
||||
std::unique_ptr<AbstractFramebuffer>
|
||||
CreateFramebuffer(const AbstractTexture* color_attachment,
|
||||
const AbstractTexture* depth_attachment) override;
|
||||
|
||||
std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage, const char* source,
|
||||
size_t length) override;
|
||||
|
@ -35,6 +35,16 @@ GLenum GetGLInternalFormatForTextureFormat(AbstractTextureFormat format, bool st
|
||||
return storage ? GL_RGBA8 : GL_RGBA;
|
||||
case AbstractTextureFormat::BGRA8:
|
||||
return storage ? GL_RGBA8 : GL_BGRA;
|
||||
case AbstractTextureFormat::R16:
|
||||
return GL_R16;
|
||||
case AbstractTextureFormat::R32F:
|
||||
return GL_R32F;
|
||||
case AbstractTextureFormat::D16:
|
||||
return GL_DEPTH_COMPONENT16;
|
||||
case AbstractTextureFormat::D32F:
|
||||
return GL_DEPTH_COMPONENT32F;
|
||||
case AbstractTextureFormat::D32F_S8:
|
||||
return GL_DEPTH32F_STENCIL8;
|
||||
default:
|
||||
PanicAlert("Unhandled texture format.");
|
||||
return storage ? GL_RGBA8 : GL_RGBA;
|
||||
@ -49,6 +59,14 @@ GLenum GetGLFormatForTextureFormat(AbstractTextureFormat format)
|
||||
return GL_RGBA;
|
||||
case AbstractTextureFormat::BGRA8:
|
||||
return GL_BGRA;
|
||||
case AbstractTextureFormat::R16:
|
||||
case AbstractTextureFormat::R32F:
|
||||
return GL_RED;
|
||||
case AbstractTextureFormat::D16:
|
||||
case AbstractTextureFormat::D32F:
|
||||
return GL_DEPTH_COMPONENT;
|
||||
case AbstractTextureFormat::D32F_S8:
|
||||
return GL_DEPTH_STENCIL;
|
||||
// Compressed texture formats don't use this parameter.
|
||||
default:
|
||||
return GL_UNSIGNED_BYTE;
|
||||
@ -62,6 +80,16 @@ GLenum GetGLTypeForTextureFormat(AbstractTextureFormat format)
|
||||
case AbstractTextureFormat::RGBA8:
|
||||
case AbstractTextureFormat::BGRA8:
|
||||
return GL_UNSIGNED_BYTE;
|
||||
case AbstractTextureFormat::R16:
|
||||
return GL_UNSIGNED_SHORT;
|
||||
case AbstractTextureFormat::R32F:
|
||||
return GL_FLOAT;
|
||||
case AbstractTextureFormat::D16:
|
||||
return GL_UNSIGNED_SHORT;
|
||||
case AbstractTextureFormat::D32F:
|
||||
return GL_FLOAT;
|
||||
case AbstractTextureFormat::D32F_S8:
|
||||
return GL_FLOAT_32_UNSIGNED_INT_24_8_REV;
|
||||
// Compressed texture formats don't use this parameter.
|
||||
default:
|
||||
return GL_UNSIGNED_BYTE;
|
||||
@ -80,38 +108,50 @@ bool UsePersistentStagingBuffers()
|
||||
|
||||
OGLTexture::OGLTexture(const TextureConfig& tex_config) : AbstractTexture(tex_config)
|
||||
{
|
||||
_dbg_assert_msg_(VIDEO, !tex_config.IsMultisampled() || tex_config.levels == 1,
|
||||
"OpenGL does not support multisampled textures with mip levels");
|
||||
|
||||
GLenum target =
|
||||
tex_config.IsMultisampled() ? GL_TEXTURE_2D_MULTISAMPLE_ARRAY : GL_TEXTURE_2D_ARRAY;
|
||||
glGenTextures(1, &m_texId);
|
||||
|
||||
glActiveTexture(GL_TEXTURE9);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, m_texId);
|
||||
glBindTexture(target, m_texId);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, m_config.levels - 1);
|
||||
glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, m_config.levels - 1);
|
||||
|
||||
if (g_ogl_config.bSupportsTextureStorage)
|
||||
GLenum gl_internal_format = GetGLInternalFormatForTextureFormat(m_config.format, true);
|
||||
if (tex_config.IsMultisampled())
|
||||
{
|
||||
GLenum gl_internal_format = GetGLInternalFormatForTextureFormat(m_config.format, true);
|
||||
glTexStorage3D(GL_TEXTURE_2D_ARRAY, m_config.levels, gl_internal_format, m_config.width,
|
||||
m_config.height, m_config.layers);
|
||||
if (g_ogl_config.bSupportsTextureStorage)
|
||||
glTexStorage3DMultisample(target, tex_config.samples, gl_internal_format, m_config.width,
|
||||
m_config.height, m_config.layers, GL_FALSE);
|
||||
else
|
||||
glTexImage3DMultisample(target, tex_config.samples, gl_internal_format, m_config.width,
|
||||
m_config.height, m_config.layers, GL_FALSE);
|
||||
}
|
||||
else if (g_ogl_config.bSupportsTextureStorage)
|
||||
{
|
||||
glTexStorage3D(target, m_config.levels, gl_internal_format, m_config.width, m_config.height,
|
||||
m_config.layers);
|
||||
}
|
||||
|
||||
if (m_config.rendertarget)
|
||||
{
|
||||
// We can't render to compressed formats.
|
||||
_assert_(!IsCompressedFormat(m_config.format));
|
||||
|
||||
if (!g_ogl_config.bSupportsTextureStorage)
|
||||
if (!g_ogl_config.bSupportsTextureStorage && !tex_config.IsMultisampled())
|
||||
{
|
||||
for (u32 level = 0; level < m_config.levels; level++)
|
||||
{
|
||||
glTexImage3D(GL_TEXTURE_2D_ARRAY, level, GL_RGBA, std::max(m_config.width >> level, 1u),
|
||||
glTexImage3D(target, level, GL_RGBA, std::max(m_config.width >> level, 1u),
|
||||
std::max(m_config.height >> level, 1u), m_config.layers, 0, GL_RGBA,
|
||||
GL_UNSIGNED_BYTE, nullptr);
|
||||
}
|
||||
}
|
||||
glGenFramebuffers(1, &m_framebuffer);
|
||||
FramebufferManager::SetFramebuffer(m_framebuffer);
|
||||
FramebufferManager::FramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
GL_TEXTURE_2D_ARRAY, m_texId, 0);
|
||||
FramebufferManager::FramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, m_texId,
|
||||
0);
|
||||
|
||||
// We broke the framebuffer binding here, and need to restore it, as the CreateTexture
|
||||
// method is in the base renderer class and can be called by VideoCommon.
|
||||
@ -156,47 +196,60 @@ void OGLTexture::CopyRectangleFromTexture(const AbstractTexture* src,
|
||||
}
|
||||
else
|
||||
{
|
||||
// If it isn't a single leveled/layered texture, we need to update the framebuffer.
|
||||
bool update_src_framebuffer =
|
||||
srcentry->m_framebuffer == 0 || srcentry->m_config.layers != 0 || src_level != 0;
|
||||
bool update_dst_framebuffer = m_framebuffer == 0 || m_config.layers != 0 || dst_level != 0;
|
||||
if (!m_framebuffer)
|
||||
glGenFramebuffers(1, &m_framebuffer);
|
||||
if (!srcentry->m_framebuffer)
|
||||
glGenFramebuffers(1, &const_cast<OGLTexture*>(srcentry)->m_framebuffer);
|
||||
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, srcentry->m_framebuffer);
|
||||
if (update_src_framebuffer)
|
||||
{
|
||||
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, srcentry->m_texId,
|
||||
src_level, src_layer);
|
||||
}
|
||||
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_framebuffer);
|
||||
if (update_dst_framebuffer)
|
||||
{
|
||||
glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texId, dst_level,
|
||||
dst_layer);
|
||||
}
|
||||
|
||||
glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom, dst_rect.left,
|
||||
dst_rect.top, dst_rect.right, dst_rect.bottom, GL_COLOR_BUFFER_BIT,
|
||||
GL_NEAREST);
|
||||
|
||||
if (update_src_framebuffer)
|
||||
{
|
||||
FramebufferManager::FramebufferTexture(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
GL_TEXTURE_2D_ARRAY, srcentry->m_texId, 0);
|
||||
}
|
||||
if (update_dst_framebuffer)
|
||||
{
|
||||
FramebufferManager::FramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
GL_TEXTURE_2D_ARRAY, m_texId, 0);
|
||||
}
|
||||
|
||||
FramebufferManager::SetFramebuffer(0);
|
||||
BlitFramebuffer(const_cast<OGLTexture*>(srcentry), src_rect, src_layer, src_level, dst_rect,
|
||||
dst_layer, dst_level);
|
||||
}
|
||||
}
|
||||
|
||||
void OGLTexture::BlitFramebuffer(OGLTexture* srcentry, const MathUtil::Rectangle<int>& src_rect,
|
||||
u32 src_layer, u32 src_level,
|
||||
const MathUtil::Rectangle<int>& dst_rect, u32 dst_layer,
|
||||
u32 dst_level)
|
||||
{
|
||||
// If it isn't a single leveled/layered texture, we need to update the framebuffer.
|
||||
bool update_src_framebuffer =
|
||||
srcentry->m_framebuffer == 0 || srcentry->m_config.layers != 0 || src_level != 0;
|
||||
bool update_dst_framebuffer = m_framebuffer == 0 || m_config.layers != 0 || dst_level != 0;
|
||||
if (!m_framebuffer)
|
||||
glGenFramebuffers(1, &m_framebuffer);
|
||||
if (!srcentry->m_framebuffer)
|
||||
glGenFramebuffers(1, &const_cast<OGLTexture*>(srcentry)->m_framebuffer);
|
||||
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, srcentry->m_framebuffer);
|
||||
if (update_src_framebuffer)
|
||||
{
|
||||
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, srcentry->m_texId,
|
||||
src_level, src_layer);
|
||||
}
|
||||
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_framebuffer);
|
||||
if (update_dst_framebuffer)
|
||||
{
|
||||
glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texId, dst_level,
|
||||
dst_layer);
|
||||
}
|
||||
|
||||
glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom, dst_rect.left,
|
||||
dst_rect.top, dst_rect.right, dst_rect.bottom, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
|
||||
if (update_src_framebuffer)
|
||||
{
|
||||
FramebufferManager::FramebufferTexture(
|
||||
GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
srcentry->m_config.IsMultisampled() ? GL_TEXTURE_2D_MULTISAMPLE_ARRAY : GL_TEXTURE_2D_ARRAY,
|
||||
srcentry->m_texId, 0);
|
||||
}
|
||||
if (update_dst_framebuffer)
|
||||
{
|
||||
FramebufferManager::FramebufferTexture(
|
||||
GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
m_config.IsMultisampled() ? GL_TEXTURE_2D_MULTISAMPLE_ARRAY : GL_TEXTURE_2D_ARRAY, m_texId,
|
||||
0);
|
||||
}
|
||||
|
||||
FramebufferManager::SetFramebuffer(0);
|
||||
}
|
||||
|
||||
void OGLTexture::ScaleRectangleFromTexture(const AbstractTexture* source,
|
||||
const MathUtil::Rectangle<int>& srcrect,
|
||||
const MathUtil::Rectangle<int>& dstrect)
|
||||
@ -219,10 +272,21 @@ void OGLTexture::ScaleRectangleFromTexture(const AbstractTexture* source,
|
||||
glUniform4f(TextureCache::GetInstance()->GetColorCopyPositionUniform(), float(srcrect.left),
|
||||
float(srcrect.top), float(srcrect.GetWidth()), float(srcrect.GetHeight()));
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
FramebufferManager::SetFramebuffer(0);
|
||||
g_renderer->RestoreAPIState();
|
||||
}
|
||||
|
||||
void OGLTexture::ResolveFromTexture(const AbstractTexture* src,
|
||||
const MathUtil::Rectangle<int>& rect, u32 layer, u32 level)
|
||||
{
|
||||
const OGLTexture* srcentry = static_cast<const OGLTexture*>(src);
|
||||
_dbg_assert_(VIDEO, m_config.samples > 1 && m_config.width == srcentry->m_config.width &&
|
||||
m_config.height == srcentry->m_config.height && m_config.samples == 1);
|
||||
_dbg_assert_(VIDEO,
|
||||
rect.left + rect.GetWidth() <= static_cast<int>(srcentry->m_config.width) &&
|
||||
rect.top + rect.GetHeight() <= static_cast<int>(srcentry->m_config.height));
|
||||
BlitFramebuffer(const_cast<OGLTexture*>(srcentry), rect, layer, level, rect, layer, level);
|
||||
}
|
||||
|
||||
void OGLTexture::Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer,
|
||||
size_t buffer_size)
|
||||
{
|
||||
@ -529,4 +593,72 @@ void OGLStagingTexture::Unmap()
|
||||
m_map_pointer = nullptr;
|
||||
}
|
||||
|
||||
OGLFramebuffer::OGLFramebuffer(AbstractTextureFormat color_format,
|
||||
AbstractTextureFormat depth_format, u32 width, u32 height,
|
||||
u32 layers, u32 samples, GLuint fbo)
|
||||
: AbstractFramebuffer(color_format, depth_format, width, height, layers, samples), m_fbo(fbo)
|
||||
{
|
||||
}
|
||||
|
||||
OGLFramebuffer::~OGLFramebuffer()
|
||||
{
|
||||
glDeleteFramebuffers(1, &m_fbo);
|
||||
}
|
||||
|
||||
std::unique_ptr<OGLFramebuffer> OGLFramebuffer::Create(const OGLTexture* color_attachment,
|
||||
const OGLTexture* depth_attachment)
|
||||
{
|
||||
if (!ValidateConfig(color_attachment, depth_attachment))
|
||||
return nullptr;
|
||||
|
||||
const AbstractTextureFormat color_format =
|
||||
color_attachment ? color_attachment->GetFormat() : AbstractTextureFormat::Undefined;
|
||||
const AbstractTextureFormat depth_format =
|
||||
depth_attachment ? depth_attachment->GetFormat() : AbstractTextureFormat::Undefined;
|
||||
const OGLTexture* either_attachment = color_attachment ? color_attachment : depth_attachment;
|
||||
const u32 width = either_attachment->GetWidth();
|
||||
const u32 height = either_attachment->GetHeight();
|
||||
const u32 layers = either_attachment->GetLayers();
|
||||
const u32 samples = either_attachment->GetSamples();
|
||||
|
||||
GLuint fbo;
|
||||
glGenFramebuffers(1, &fbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
|
||||
if (color_attachment)
|
||||
{
|
||||
if (color_attachment->GetConfig().layers > 1)
|
||||
{
|
||||
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
color_attachment->GetRawTexIdentifier(), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
color_attachment->GetRawTexIdentifier(), 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (depth_attachment)
|
||||
{
|
||||
GLenum attachment = AbstractTexture::IsStencilFormat(depth_format) ?
|
||||
GL_DEPTH_STENCIL_ATTACHMENT :
|
||||
GL_DEPTH_ATTACHMENT;
|
||||
if (depth_attachment->GetConfig().layers > 1)
|
||||
{
|
||||
glFramebufferTexture(GL_FRAMEBUFFER, attachment, depth_attachment->GetRawTexIdentifier(), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
glFramebufferTextureLayer(GL_FRAMEBUFFER, attachment, depth_attachment->GetRawTexIdentifier(),
|
||||
0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
_dbg_assert_(VIDEO, glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
|
||||
FramebufferManager::SetFramebuffer(0);
|
||||
return std::make_unique<OGLFramebuffer>(color_format, depth_format, width, height, layers,
|
||||
samples, fbo);
|
||||
}
|
||||
|
||||
} // namespace OGL
|
||||
|
@ -4,10 +4,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "Common/GL/GLUtil.h"
|
||||
|
||||
#include "VideoCommon/AbstractFramebuffer.h"
|
||||
#include "VideoCommon/AbstractStagingTexture.h"
|
||||
#include "VideoCommon/AbstractTexture.h"
|
||||
|
||||
@ -26,6 +28,8 @@ public:
|
||||
void ScaleRectangleFromTexture(const AbstractTexture* source,
|
||||
const MathUtil::Rectangle<int>& srcrect,
|
||||
const MathUtil::Rectangle<int>& dstrect) override;
|
||||
void ResolveFromTexture(const AbstractTexture* src, const MathUtil::Rectangle<int>& rect,
|
||||
u32 layer, u32 level) override;
|
||||
void Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer,
|
||||
size_t buffer_size) override;
|
||||
|
||||
@ -33,6 +37,10 @@ public:
|
||||
GLuint GetFramebuffer() const;
|
||||
|
||||
private:
|
||||
void BlitFramebuffer(OGLTexture* srcentry, const MathUtil::Rectangle<int>& src_rect,
|
||||
u32 src_layer, u32 src_level, const MathUtil::Rectangle<int>& dst_rect,
|
||||
u32 dst_layer, u32 dst_level);
|
||||
|
||||
GLuint m_texId;
|
||||
GLuint m_framebuffer = 0;
|
||||
};
|
||||
@ -68,4 +76,19 @@ private:
|
||||
GLsync m_fence = 0;
|
||||
};
|
||||
|
||||
class OGLFramebuffer final : public AbstractFramebuffer
|
||||
{
|
||||
public:
|
||||
OGLFramebuffer(AbstractTextureFormat color_format, AbstractTextureFormat depth_format, u32 width,
|
||||
u32 height, u32 layers, u32 samples, GLuint fbo);
|
||||
~OGLFramebuffer() override;
|
||||
|
||||
GLuint GetFBO() const { return m_fbo; }
|
||||
static std::unique_ptr<OGLFramebuffer> Create(const OGLTexture* color_attachment,
|
||||
const OGLTexture* depth_attachment);
|
||||
|
||||
protected:
|
||||
GLuint m_fbo;
|
||||
};
|
||||
|
||||
} // namespace OGL
|
||||
|
@ -827,6 +827,8 @@ void Renderer::Init()
|
||||
// Initialize the FramebufferManager
|
||||
g_framebuffer_manager = std::make_unique<FramebufferManager>(
|
||||
m_target_width, m_target_height, s_MSAASamples, BoundingBox::NeedsStencilBuffer());
|
||||
m_current_framebuffer_width = m_target_width;
|
||||
m_current_framebuffer_height = m_target_height;
|
||||
|
||||
m_post_processor = std::make_unique<OpenGLPostProcessing>();
|
||||
s_raster_font = std::make_unique<RasterFont>();
|
||||
@ -843,6 +845,14 @@ std::unique_ptr<AbstractStagingTexture> Renderer::CreateStagingTexture(StagingTe
|
||||
return OGLStagingTexture::Create(type, config);
|
||||
}
|
||||
|
||||
std::unique_ptr<AbstractFramebuffer>
|
||||
Renderer::CreateFramebuffer(const AbstractTexture* color_attachment,
|
||||
const AbstractTexture* depth_attachment)
|
||||
{
|
||||
return OGLFramebuffer::Create(static_cast<const OGLTexture*>(color_attachment),
|
||||
static_cast<const OGLTexture*>(depth_attachment));
|
||||
}
|
||||
|
||||
void Renderer::RenderText(const std::string& text, int left, int top, u32 color)
|
||||
{
|
||||
s_raster_font->printMultilineText(text,
|
||||
@ -1145,7 +1155,7 @@ void Renderer::SetViewport(float x, float y, float width, float height, float ne
|
||||
{
|
||||
// The x/y parameters here assume a upper-left origin. glViewport takes an offset from the
|
||||
// lower-left of the framebuffer, so we must set y to the distance from the lower-left.
|
||||
y = static_cast<float>(m_target_height) - y - height;
|
||||
y = static_cast<float>(m_current_framebuffer_height) - y - height;
|
||||
if (g_ogl_config.bSupportViewportFloat)
|
||||
{
|
||||
glViewportIndexedf(0, x, y, width, height);
|
||||
@ -1238,6 +1248,44 @@ void Renderer::ReinterpretPixelData(unsigned int convtype)
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::SetFramebuffer(const AbstractFramebuffer* framebuffer)
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, static_cast<const OGLFramebuffer*>(framebuffer)->GetFBO());
|
||||
m_current_framebuffer = framebuffer;
|
||||
m_current_framebuffer_width = framebuffer->GetWidth();
|
||||
m_current_framebuffer_height = framebuffer->GetHeight();
|
||||
}
|
||||
|
||||
void Renderer::SetAndDiscardFramebuffer(const AbstractFramebuffer* framebuffer)
|
||||
{
|
||||
// EXT_discard_framebuffer could be used here to save bandwidth on tilers.
|
||||
SetFramebuffer(framebuffer);
|
||||
}
|
||||
|
||||
void Renderer::SetAndClearFramebuffer(const AbstractFramebuffer* framebuffer,
|
||||
const ClearColor& color_value, float depth_value)
|
||||
{
|
||||
SetFramebuffer(framebuffer);
|
||||
|
||||
// NOTE: This disturbs the current scissor/mask setting.
|
||||
// This won't be an issue when we implement proper state tracking.
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
GLbitfield clear_mask = 0;
|
||||
if (framebuffer->HasColorBuffer())
|
||||
{
|
||||
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||
glClearColor(color_value[0], color_value[1], color_value[2], color_value[3]);
|
||||
clear_mask |= GL_COLOR_BUFFER_BIT;
|
||||
}
|
||||
if (framebuffer->HasDepthBuffer())
|
||||
{
|
||||
glDepthMask(GL_TRUE);
|
||||
glClearDepth(depth_value);
|
||||
clear_mask |= GL_DEPTH_BUFFER_BIT;
|
||||
}
|
||||
glClear(clear_mask);
|
||||
}
|
||||
|
||||
void Renderer::ApplyBlendingState(const BlendingState& state)
|
||||
{
|
||||
bool useDualSource =
|
||||
@ -1351,6 +1399,9 @@ void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
glClearColor(0, 0, 0, 0);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
m_current_framebuffer = nullptr;
|
||||
m_current_framebuffer_width = m_backbuffer_width;
|
||||
m_current_framebuffer_height = m_backbuffer_height;
|
||||
|
||||
// Copy the framebuffer to screen.
|
||||
BlitScreen(sourceRc, flipped_trc, xfb_texture->GetRawTexIdentifier(),
|
||||
@ -1416,9 +1467,6 @@ void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region
|
||||
g_texture_cache->Cleanup(frameCount);
|
||||
ProgramShaderCache::RetrieveAsyncShaders();
|
||||
|
||||
// Render to the framebuffer.
|
||||
FramebufferManager::SetFramebuffer(0);
|
||||
|
||||
RestoreAPIState();
|
||||
|
||||
g_Config.iSaveTargetId = 0;
|
||||
@ -1499,6 +1547,11 @@ void Renderer::ResetAPIState()
|
||||
|
||||
void Renderer::RestoreAPIState()
|
||||
{
|
||||
m_current_framebuffer = nullptr;
|
||||
m_current_framebuffer_width = m_target_width;
|
||||
m_current_framebuffer_height = m_target_height;
|
||||
FramebufferManager::SetFramebuffer(0);
|
||||
|
||||
// Gets us back into a more game-like state.
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
if (g_ActiveConfig.backend_info.bSupportsDepthClamp)
|
||||
|
@ -95,8 +95,16 @@ public:
|
||||
std::unique_ptr<AbstractShader> CreateShaderFromBinary(ShaderStage stage, const void* data,
|
||||
size_t length) override;
|
||||
std::unique_ptr<AbstractPipeline> CreatePipeline(const AbstractPipelineConfig& config) override;
|
||||
std::unique_ptr<AbstractFramebuffer>
|
||||
CreateFramebuffer(const AbstractTexture* color_attachment,
|
||||
const AbstractTexture* depth_attachment) override;
|
||||
|
||||
void SetPipeline(const AbstractPipeline* pipeline) override;
|
||||
void SetFramebuffer(const AbstractFramebuffer* framebuffer) override;
|
||||
void SetAndDiscardFramebuffer(const AbstractFramebuffer* framebuffer) override;
|
||||
void SetAndClearFramebuffer(const AbstractFramebuffer* framebuffer,
|
||||
const ClearColor& color_value = {},
|
||||
float depth_value = 0.0f) override;
|
||||
void SetBlendingState(const BlendingState& state) override;
|
||||
void SetScissorRect(const MathUtil::Rectangle<int>& rc) override;
|
||||
void SetRasterizationState(const RasterizationState& state) override;
|
||||
|
@ -323,7 +323,6 @@ void TextureCache::ConvertTexture(TCacheEntry* destination, TCacheEntry* source,
|
||||
ProgramShaderCache::BindVertexFormat(nullptr);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
FramebufferManager::SetFramebuffer(0);
|
||||
g_renderer->RestoreAPIState();
|
||||
}
|
||||
|
||||
@ -540,7 +539,6 @@ void TextureCache::CopyEFBToCacheEntry(TCacheEntry* entry, bool is_depth_copy,
|
||||
ProgramShaderCache::BindVertexFormat(nullptr);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
FramebufferManager::SetFramebuffer(0);
|
||||
g_renderer->RestoreAPIState();
|
||||
}
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ static EncodingProgram& GetOrCreateEncodingShader(const EFBCopyParams& params)
|
||||
|
||||
void Init()
|
||||
{
|
||||
TextureConfig config(renderBufferWidth, renderBufferHeight, 1, 1, AbstractTextureFormat::BGRA8,
|
||||
TextureConfig config(renderBufferWidth, renderBufferHeight, 1, 1, 1, AbstractTextureFormat::BGRA8,
|
||||
true);
|
||||
s_encoding_render_texture = g_renderer->CreateTexture(config);
|
||||
s_encoding_readback_texture =
|
||||
@ -133,8 +133,6 @@ static void EncodeToRamUsingShader(GLuint srcTexture, u8* destAddr, u32 dst_line
|
||||
s_encoding_readback_texture->CopyFromTexture(s_encoding_render_texture.get(), copy_rect, 0, 0,
|
||||
copy_rect);
|
||||
s_encoding_readback_texture->ReadTexels(copy_rect, destAddr, writeStride);
|
||||
|
||||
FramebufferManager::SetFramebuffer(0);
|
||||
}
|
||||
|
||||
void EncodeToRamFromTexture(u8* dest_ptr, const EFBCopyParams& params, u32 native_width,
|
||||
@ -157,7 +155,6 @@ void EncodeToRamFromTexture(u8* dest_ptr, const EFBCopyParams& params, u32 nativ
|
||||
EncodeToRamUsingShader(read_texture, dest_ptr, bytes_per_row, num_blocks_y, memory_stride,
|
||||
scale_by_half && !params.depth, params.y_scale);
|
||||
|
||||
FramebufferManager::SetFramebuffer(0);
|
||||
g_renderer->RestoreAPIState();
|
||||
}
|
||||
|
||||
|
@ -39,6 +39,14 @@ SWRenderer::CreateStagingTexture(StagingTextureType type, const TextureConfig& c
|
||||
return std::make_unique<SW::SWStagingTexture>(type, config);
|
||||
}
|
||||
|
||||
std::unique_ptr<AbstractFramebuffer>
|
||||
SWRenderer::CreateFramebuffer(const AbstractTexture* color_attachment,
|
||||
const AbstractTexture* depth_attachment)
|
||||
{
|
||||
return SW::SWFramebuffer::Create(static_cast<const SW::SWTexture*>(color_attachment),
|
||||
static_cast<const SW::SWTexture*>(depth_attachment));
|
||||
}
|
||||
|
||||
void SWRenderer::RenderText(const std::string& pstr, int left, int top, u32 color)
|
||||
{
|
||||
SWOGLWindow::s_instance->PrintText(pstr, left, top, color);
|
||||
|
@ -16,6 +16,9 @@ public:
|
||||
std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config) override;
|
||||
std::unique_ptr<AbstractStagingTexture>
|
||||
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override;
|
||||
std::unique_ptr<AbstractFramebuffer>
|
||||
CreateFramebuffer(const AbstractTexture* color_attachment,
|
||||
const AbstractTexture* depth_attachment) override;
|
||||
|
||||
std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage, const char* source,
|
||||
size_t length) override;
|
||||
|
@ -86,6 +86,10 @@ void SWTexture::ScaleRectangleFromTexture(const AbstractTexture* source,
|
||||
memcpy(GetData(), destination_pixels.data(), destination_pixels.size());
|
||||
}
|
||||
}
|
||||
void SWTexture::ResolveFromTexture(const AbstractTexture* src, const MathUtil::Rectangle<int>& rect,
|
||||
u32 layer, u32 level)
|
||||
{
|
||||
}
|
||||
|
||||
void SWTexture::Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer,
|
||||
size_t buffer_size)
|
||||
@ -148,4 +152,31 @@ void SWStagingTexture::Flush()
|
||||
{
|
||||
m_needs_flush = false;
|
||||
}
|
||||
|
||||
SWFramebuffer::SWFramebuffer(AbstractTextureFormat color_format, AbstractTextureFormat depth_format,
|
||||
u32 width, u32 height, u32 layers, u32 samples)
|
||||
: AbstractFramebuffer(color_format, depth_format, width, height, layers, samples)
|
||||
{
|
||||
}
|
||||
|
||||
std::unique_ptr<SWFramebuffer> SWFramebuffer::Create(const SWTexture* color_attachment,
|
||||
const SWTexture* depth_attachment)
|
||||
{
|
||||
if (!ValidateConfig(color_attachment, depth_attachment))
|
||||
return nullptr;
|
||||
|
||||
const AbstractTextureFormat color_format =
|
||||
color_attachment ? color_attachment->GetFormat() : AbstractTextureFormat::Undefined;
|
||||
const AbstractTextureFormat depth_format =
|
||||
depth_attachment ? depth_attachment->GetFormat() : AbstractTextureFormat::Undefined;
|
||||
const SWTexture* either_attachment = color_attachment ? color_attachment : depth_attachment;
|
||||
const u32 width = either_attachment->GetWidth();
|
||||
const u32 height = either_attachment->GetHeight();
|
||||
const u32 layers = either_attachment->GetLayers();
|
||||
const u32 samples = either_attachment->GetSamples();
|
||||
|
||||
return std::make_unique<SWFramebuffer>(color_format, depth_format, width, height, layers,
|
||||
samples);
|
||||
}
|
||||
|
||||
} // namespace SW
|
||||
|
@ -4,10 +4,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
#include "VideoCommon/AbstractFramebuffer.h"
|
||||
#include "VideoCommon/AbstractStagingTexture.h"
|
||||
#include "VideoCommon/AbstractTexture.h"
|
||||
|
||||
@ -26,6 +28,8 @@ public:
|
||||
void ScaleRectangleFromTexture(const AbstractTexture* source,
|
||||
const MathUtil::Rectangle<int>& srcrect,
|
||||
const MathUtil::Rectangle<int>& dstrect) override;
|
||||
void ResolveFromTexture(const AbstractTexture* src, const MathUtil::Rectangle<int>& rect,
|
||||
u32 layer, u32 level) override;
|
||||
void Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer,
|
||||
size_t buffer_size) override;
|
||||
|
||||
@ -57,4 +61,15 @@ private:
|
||||
std::vector<u8> m_data;
|
||||
};
|
||||
|
||||
class SWFramebuffer final : public AbstractFramebuffer
|
||||
{
|
||||
public:
|
||||
explicit SWFramebuffer(AbstractTextureFormat color_format, AbstractTextureFormat depth_format,
|
||||
u32 width, u32 height, u32 layers, u32 samples);
|
||||
~SWFramebuffer() override = default;
|
||||
|
||||
static std::unique_ptr<SWFramebuffer> Create(const SWTexture* color_attachment,
|
||||
const SWTexture* depth_attachment);
|
||||
};
|
||||
|
||||
} // namespace SW
|
||||
|
@ -846,8 +846,8 @@ bool FramebufferManager::CreateReadbackTextures()
|
||||
return false;
|
||||
}
|
||||
|
||||
TextureConfig readback_texture_config(EFB_WIDTH, EFB_HEIGHT, 1, 1, AbstractTextureFormat::RGBA8,
|
||||
false);
|
||||
TextureConfig readback_texture_config(EFB_WIDTH, EFB_HEIGHT, 1, 1, 1,
|
||||
AbstractTextureFormat::RGBA8, false);
|
||||
m_color_readback_texture =
|
||||
g_renderer->CreateStagingTexture(StagingTextureType::Mutable, readback_texture_config);
|
||||
m_depth_readback_texture =
|
||||
|
@ -192,6 +192,14 @@ std::unique_ptr<AbstractPipeline> Renderer::CreatePipeline(const AbstractPipelin
|
||||
return VKPipeline::Create(config);
|
||||
}
|
||||
|
||||
std::unique_ptr<AbstractFramebuffer>
|
||||
Renderer::CreateFramebuffer(const AbstractTexture* color_attachment,
|
||||
const AbstractTexture* depth_attachment)
|
||||
{
|
||||
return VKFramebuffer::Create(static_cast<const VKTexture*>(color_attachment),
|
||||
static_cast<const VKTexture*>(depth_attachment));
|
||||
}
|
||||
|
||||
std::tuple<VkBuffer, u32> Renderer::UpdateUtilityUniformBuffer(const void* uniforms,
|
||||
u32 uniforms_size)
|
||||
{
|
||||
@ -593,8 +601,9 @@ void Renderer::ClearScreen(const EFBRectangle& rc, bool color_enable, bool alpha
|
||||
// Fastest path: Use a render pass to clear the buffers.
|
||||
if (use_clear_render_pass)
|
||||
{
|
||||
VkClearValue clear_values[2] = {clear_color_value, clear_depth_value};
|
||||
StateTracker::GetInstance()->BeginClearRenderPass(target_vk_rc, clear_values);
|
||||
const std::array<VkClearValue, 2> clear_values = {{clear_color_value, clear_depth_value}};
|
||||
StateTracker::GetInstance()->BeginClearRenderPass(target_vk_rc, clear_values.data(),
|
||||
static_cast<u32>(clear_values.size()));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -743,6 +752,7 @@ void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region
|
||||
// Restore the EFB color texture to color attachment ready for rendering the next frame.
|
||||
FramebufferManager::GetInstance()->GetEFBColorTexture()->TransitionToLayout(
|
||||
g_command_buffer_mgr->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
RestoreAPIState();
|
||||
|
||||
// Determine what (if anything) has changed in the config.
|
||||
CheckForConfigChanges();
|
||||
@ -792,6 +802,9 @@ void Renderer::DrawScreen(VKTexture* xfb_texture, const EFBRectangle& xfb_region
|
||||
backbuffer->OverrideImageLayout(VK_IMAGE_LAYOUT_UNDEFINED);
|
||||
backbuffer->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
m_current_framebuffer = nullptr;
|
||||
m_current_framebuffer_width = backbuffer->GetWidth();
|
||||
m_current_framebuffer_height = backbuffer->GetHeight();
|
||||
|
||||
// Begin render pass for rendering to the swap chain.
|
||||
VkClearValue clear_value = {{{0.0f, 0.0f, 0.0f, 1.0f}}};
|
||||
@ -1010,6 +1023,9 @@ void Renderer::BindEFBToStateTracker()
|
||||
FramebufferManager::GetInstance()->GetEFBFramebuffer(), framebuffer_size);
|
||||
StateTracker::GetInstance()->SetMultisamplingstate(
|
||||
FramebufferManager::GetInstance()->GetEFBMultisamplingState());
|
||||
m_current_framebuffer = nullptr;
|
||||
m_current_framebuffer_width = FramebufferManager::GetInstance()->GetEFBWidth();
|
||||
m_current_framebuffer_height = FramebufferManager::GetInstance()->GetEFBHeight();
|
||||
}
|
||||
|
||||
void Renderer::RecreateEFBFramebuffer()
|
||||
@ -1036,10 +1052,79 @@ void Renderer::ResetAPIState()
|
||||
|
||||
void Renderer::RestoreAPIState()
|
||||
{
|
||||
StateTracker::GetInstance()->EndRenderPass();
|
||||
if (m_current_framebuffer)
|
||||
static_cast<const VKFramebuffer*>(m_current_framebuffer)->TransitionForSample();
|
||||
|
||||
BindEFBToStateTracker();
|
||||
|
||||
// Instruct the state tracker to re-bind everything before the next draw
|
||||
StateTracker::GetInstance()->SetPendingRebind();
|
||||
}
|
||||
|
||||
void Renderer::BindFramebuffer(const VKFramebuffer* fb)
|
||||
{
|
||||
const VkRect2D render_area = {static_cast<int>(fb->GetWidth()),
|
||||
static_cast<int>(fb->GetHeight())};
|
||||
|
||||
StateTracker::GetInstance()->EndRenderPass();
|
||||
if (m_current_framebuffer)
|
||||
static_cast<const VKFramebuffer*>(m_current_framebuffer)->TransitionForSample();
|
||||
|
||||
fb->TransitionForRender();
|
||||
StateTracker::GetInstance()->SetFramebuffer(fb->GetFB(), render_area);
|
||||
StateTracker::GetInstance()->SetRenderPass(fb->GetLoadRenderPass(), fb->GetClearRenderPass());
|
||||
m_current_framebuffer = fb;
|
||||
m_current_framebuffer_width = fb->GetWidth();
|
||||
m_current_framebuffer_height = fb->GetHeight();
|
||||
}
|
||||
|
||||
void Renderer::SetFramebuffer(const AbstractFramebuffer* framebuffer)
|
||||
{
|
||||
const VKFramebuffer* vkfb = static_cast<const VKFramebuffer*>(framebuffer);
|
||||
BindFramebuffer(vkfb);
|
||||
StateTracker::GetInstance()->BeginRenderPass();
|
||||
}
|
||||
|
||||
void Renderer::SetAndDiscardFramebuffer(const AbstractFramebuffer* framebuffer)
|
||||
{
|
||||
const VKFramebuffer* vkfb = static_cast<const VKFramebuffer*>(framebuffer);
|
||||
BindFramebuffer(vkfb);
|
||||
|
||||
// If we're discarding, begin the discard pass, then switch to a load pass.
|
||||
// This way if the command buffer is flushed, we don't start another discard pass.
|
||||
StateTracker::GetInstance()->SetRenderPass(vkfb->GetDiscardRenderPass(),
|
||||
vkfb->GetClearRenderPass());
|
||||
StateTracker::GetInstance()->BeginRenderPass();
|
||||
StateTracker::GetInstance()->SetRenderPass(vkfb->GetLoadRenderPass(), vkfb->GetClearRenderPass());
|
||||
}
|
||||
|
||||
void Renderer::SetAndClearFramebuffer(const AbstractFramebuffer* framebuffer,
|
||||
const ClearColor& color_value, float depth_value)
|
||||
{
|
||||
const VKFramebuffer* vkfb = static_cast<const VKFramebuffer*>(framebuffer);
|
||||
BindFramebuffer(vkfb);
|
||||
|
||||
const VkRect2D render_area = {static_cast<int>(vkfb->GetWidth()),
|
||||
static_cast<int>(vkfb->GetHeight())};
|
||||
std::array<VkClearValue, 2> clear_values;
|
||||
u32 num_clear_values = 0;
|
||||
if (vkfb->GetColorFormat() != AbstractTextureFormat::Undefined)
|
||||
{
|
||||
std::memcpy(clear_values[num_clear_values].color.float32, color_value.data(),
|
||||
sizeof(clear_values[num_clear_values].color.float32));
|
||||
num_clear_values++;
|
||||
}
|
||||
if (vkfb->GetDepthFormat() != AbstractTextureFormat::Undefined)
|
||||
{
|
||||
clear_values[num_clear_values].depthStencil.depth = depth_value;
|
||||
clear_values[num_clear_values].depthStencil.stencil = 0;
|
||||
num_clear_values++;
|
||||
}
|
||||
StateTracker::GetInstance()->BeginClearRenderPass(render_area, clear_values.data(),
|
||||
num_clear_values);
|
||||
}
|
||||
|
||||
void Renderer::SetRasterizationState(const RasterizationState& state)
|
||||
{
|
||||
StateTracker::GetInstance()->SetRasterizationState(state);
|
||||
|
@ -23,6 +23,7 @@ class SwapChain;
|
||||
class StagingTexture2D;
|
||||
class Texture2D;
|
||||
class RasterFont;
|
||||
class VKFramebuffer;
|
||||
class VKPipeline;
|
||||
class VKTexture;
|
||||
|
||||
@ -37,6 +38,9 @@ public:
|
||||
std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config) override;
|
||||
std::unique_ptr<AbstractStagingTexture>
|
||||
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override;
|
||||
std::unique_ptr<AbstractFramebuffer>
|
||||
CreateFramebuffer(const AbstractTexture* color_attachment,
|
||||
const AbstractTexture* depth_attachment) override;
|
||||
|
||||
std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage, const char* source,
|
||||
size_t length) override;
|
||||
@ -68,6 +72,11 @@ public:
|
||||
void RestoreAPIState() override;
|
||||
|
||||
void SetPipeline(const AbstractPipeline* pipeline) override;
|
||||
void SetFramebuffer(const AbstractFramebuffer* framebuffer) override;
|
||||
void SetAndDiscardFramebuffer(const AbstractFramebuffer* framebuffer) override;
|
||||
void SetAndClearFramebuffer(const AbstractFramebuffer* framebuffer,
|
||||
const ClearColor& color_value = {},
|
||||
float depth_value = 0.0f) override;
|
||||
void SetBlendingState(const BlendingState& state) override;
|
||||
void SetScissorRect(const MathUtil::Rectangle<int>& rc) override;
|
||||
void SetRasterizationState(const RasterizationState& state) override;
|
||||
@ -99,6 +108,7 @@ private:
|
||||
void OnSwapChainResized();
|
||||
void BindEFBToStateTracker();
|
||||
void RecreateEFBFramebuffer();
|
||||
void BindFramebuffer(const VKFramebuffer* fb);
|
||||
|
||||
void RecompileShaders();
|
||||
bool CompileShaders();
|
||||
|
@ -703,7 +703,8 @@ void StateTracker::EndRenderPass()
|
||||
m_current_render_pass = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
void StateTracker::BeginClearRenderPass(const VkRect2D& area, const VkClearValue clear_values[2])
|
||||
void StateTracker::BeginClearRenderPass(const VkRect2D& area, const VkClearValue* clear_values,
|
||||
u32 num_clear_values)
|
||||
{
|
||||
_assert_(!InRenderPass());
|
||||
|
||||
@ -715,7 +716,7 @@ void StateTracker::BeginClearRenderPass(const VkRect2D& area, const VkClearValue
|
||||
m_current_render_pass,
|
||||
m_framebuffer,
|
||||
m_framebuffer_render_area,
|
||||
2,
|
||||
num_clear_values,
|
||||
clear_values};
|
||||
|
||||
vkCmdBeginRenderPass(g_command_buffer_mgr->GetCurrentCommandBuffer(), &begin_info,
|
||||
|
@ -45,6 +45,7 @@ public:
|
||||
{
|
||||
return m_bindings.ps_samplers;
|
||||
}
|
||||
VkFramebuffer GetFramebuffer() const { return m_framebuffer; }
|
||||
void SetVertexBuffer(VkBuffer buffer, VkDeviceSize offset);
|
||||
void SetIndexBuffer(VkBuffer buffer, VkDeviceSize offset, VkIndexType type);
|
||||
|
||||
@ -90,7 +91,8 @@ public:
|
||||
void EndRenderPass();
|
||||
|
||||
// Ends the current render pass if it was a clear render pass.
|
||||
void BeginClearRenderPass(const VkRect2D& area, const VkClearValue clear_values[2]);
|
||||
void BeginClearRenderPass(const VkRect2D& area, const VkClearValue* clear_values,
|
||||
u32 num_clear_values);
|
||||
void EndClearRenderPass();
|
||||
|
||||
void SetViewport(const VkViewport& viewport);
|
||||
|
@ -596,7 +596,7 @@ VkShaderModule TextureConverter::GetEncodingShader(const EFBCopyParams& params)
|
||||
|
||||
bool TextureConverter::CreateEncodingTexture()
|
||||
{
|
||||
TextureConfig config(ENCODING_TEXTURE_WIDTH, ENCODING_TEXTURE_HEIGHT, 1, 1,
|
||||
TextureConfig config(ENCODING_TEXTURE_WIDTH, ENCODING_TEXTURE_HEIGHT, 1, 1, 1,
|
||||
ENCODING_TEXTURE_FORMAT, true);
|
||||
|
||||
m_encoding_render_texture = g_renderer->CreateTexture(config);
|
||||
|
@ -112,6 +112,21 @@ VkFormat GetVkFormatForHostTextureFormat(AbstractTextureFormat format)
|
||||
case AbstractTextureFormat::BGRA8:
|
||||
return VK_FORMAT_B8G8R8A8_UNORM;
|
||||
|
||||
case AbstractTextureFormat::R16:
|
||||
return VK_FORMAT_R16_UNORM;
|
||||
|
||||
case AbstractTextureFormat::D16:
|
||||
return VK_FORMAT_D16_UNORM;
|
||||
|
||||
case AbstractTextureFormat::R32F:
|
||||
return VK_FORMAT_R32_SFLOAT;
|
||||
|
||||
case AbstractTextureFormat::D32F:
|
||||
return VK_FORMAT_D32_SFLOAT;
|
||||
|
||||
case AbstractTextureFormat::D32F_S8:
|
||||
return VK_FORMAT_D32_SFLOAT_S8_UINT;
|
||||
|
||||
default:
|
||||
PanicAlert("Unhandled texture format.");
|
||||
return VK_FORMAT_R8G8B8A8_UNORM;
|
||||
|
@ -42,9 +42,10 @@ std::unique_ptr<VKTexture> VKTexture::Create(const TextureConfig& tex_config)
|
||||
|
||||
// Allocate texture object
|
||||
VkFormat vk_format = Util::GetVkFormatForHostTextureFormat(tex_config.format);
|
||||
auto texture = Texture2D::Create(tex_config.width, tex_config.height, tex_config.levels,
|
||||
tex_config.layers, vk_format, VK_SAMPLE_COUNT_1_BIT,
|
||||
VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_TILING_OPTIMAL, usage);
|
||||
auto texture =
|
||||
Texture2D::Create(tex_config.width, tex_config.height, tex_config.levels, tex_config.layers,
|
||||
vk_format, static_cast<VkSampleCountFlagBits>(tex_config.samples),
|
||||
VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_TILING_OPTIMAL, usage);
|
||||
|
||||
if (!texture)
|
||||
{
|
||||
@ -56,8 +57,9 @@ std::unique_ptr<VKTexture> VKTexture::Create(const TextureConfig& tex_config)
|
||||
if (tex_config.rendertarget)
|
||||
{
|
||||
VkImageView framebuffer_attachments[] = {texture->GetView()};
|
||||
VkRenderPass render_pass = g_object_cache->GetRenderPass(
|
||||
texture->GetFormat(), VK_FORMAT_UNDEFINED, 1, VK_ATTACHMENT_LOAD_OP_DONT_CARE);
|
||||
VkRenderPass render_pass =
|
||||
g_object_cache->GetRenderPass(texture->GetFormat(), VK_FORMAT_UNDEFINED, tex_config.samples,
|
||||
VK_ATTACHMENT_LOAD_OP_DONT_CARE);
|
||||
VkFramebufferCreateInfo framebuffer_info = {
|
||||
VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
||||
nullptr,
|
||||
@ -77,14 +79,29 @@ std::unique_ptr<VKTexture> VKTexture::Create(const TextureConfig& tex_config)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Clear render targets before use to prevent reading uninitialized memory.
|
||||
VkClearColorValue clear_value = {{0.0f, 0.0f, 0.0f, 1.0f}};
|
||||
VkImageSubresourceRange clear_range = {VK_IMAGE_ASPECT_COLOR_BIT, 0, tex_config.levels, 0,
|
||||
tex_config.layers};
|
||||
texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentInitCommandBuffer(),
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
vkCmdClearColorImage(g_command_buffer_mgr->GetCurrentInitCommandBuffer(), texture->GetImage(),
|
||||
texture->GetLayout(), &clear_value, 1, &clear_range);
|
||||
if (!IsDepthFormat(tex_config.format))
|
||||
{
|
||||
// Clear render targets before use to prevent reading uninitialized memory.
|
||||
VkClearColorValue clear_value = {{0.0f, 0.0f, 0.0f, 1.0f}};
|
||||
VkImageSubresourceRange clear_range = {VK_IMAGE_ASPECT_COLOR_BIT, 0, tex_config.levels, 0,
|
||||
tex_config.layers};
|
||||
texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentInitCommandBuffer(),
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
vkCmdClearColorImage(g_command_buffer_mgr->GetCurrentInitCommandBuffer(), texture->GetImage(),
|
||||
texture->GetLayout(), &clear_value, 1, &clear_range);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Clear render targets before use to prevent reading uninitialized memory.
|
||||
VkClearDepthStencilValue clear_value = {0.0f, 0};
|
||||
VkImageSubresourceRange clear_range = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, tex_config.levels, 0,
|
||||
tex_config.layers};
|
||||
texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentInitCommandBuffer(),
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
vkCmdClearDepthStencilImage(g_command_buffer_mgr->GetCurrentInitCommandBuffer(),
|
||||
texture->GetImage(), texture->GetLayout(), &clear_value, 1,
|
||||
&clear_range);
|
||||
}
|
||||
}
|
||||
|
||||
return std::unique_ptr<VKTexture>(new VKTexture(tex_config, std::move(texture), framebuffer));
|
||||
@ -195,6 +212,43 @@ void VKTexture::ScaleRectangleFromTexture(const AbstractTexture* source,
|
||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
}
|
||||
|
||||
void VKTexture::ResolveFromTexture(const AbstractTexture* src, const MathUtil::Rectangle<int>& rect,
|
||||
u32 layer, u32 level)
|
||||
{
|
||||
const VKTexture* srcentry = static_cast<const VKTexture*>(src);
|
||||
_dbg_assert_(VIDEO, m_config.samples == 1 && m_config.width == srcentry->m_config.width &&
|
||||
m_config.height == srcentry->m_config.height &&
|
||||
srcentry->m_config.samples > 1);
|
||||
_dbg_assert_(VIDEO,
|
||||
rect.left + rect.GetWidth() <= static_cast<int>(srcentry->m_config.width) &&
|
||||
rect.top + rect.GetHeight() <= static_cast<int>(srcentry->m_config.height));
|
||||
|
||||
// Resolving is considered to be a transfer operation.
|
||||
StateTracker::GetInstance()->EndRenderPass();
|
||||
VkImageLayout old_src_layout = srcentry->m_texture->GetLayout();
|
||||
srcentry->m_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||
m_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
|
||||
VkImageResolve resolve = {
|
||||
{VK_IMAGE_ASPECT_COLOR_BIT, level, layer, 1}, // srcSubresource
|
||||
{rect.left, rect.top, 0}, // srcOffset
|
||||
{VK_IMAGE_ASPECT_COLOR_BIT, level, layer, 1}, // dstSubresource
|
||||
{rect.left, rect.top, 0}, // dstOffset
|
||||
{static_cast<u32>(rect.GetWidth()), static_cast<u32>(rect.GetHeight()), 1} // extent
|
||||
};
|
||||
vkCmdResolveImage(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
||||
srcentry->m_texture->GetImage(), srcentry->m_texture->GetLayout(),
|
||||
m_texture->GetImage(), m_texture->GetLayout(), 1, &resolve);
|
||||
|
||||
// Restore old source texture layout. Destination is assumed to be bound as a shader resource.
|
||||
srcentry->m_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
||||
old_src_layout);
|
||||
m_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
}
|
||||
|
||||
void VKTexture::Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer,
|
||||
size_t buffer_size)
|
||||
{
|
||||
@ -512,4 +566,118 @@ void VKStagingTexture::Flush()
|
||||
m_staging_buffer->InvalidateCPUCache();
|
||||
}
|
||||
|
||||
VKFramebuffer::VKFramebuffer(const VKTexture* color_attachment, const VKTexture* depth_attachment,
|
||||
u32 width, u32 height, u32 layers, u32 samples, VkFramebuffer fb,
|
||||
VkRenderPass load_render_pass, VkRenderPass discard_render_pass,
|
||||
VkRenderPass clear_render_pass)
|
||||
: AbstractFramebuffer(
|
||||
color_attachment ? color_attachment->GetFormat() : AbstractTextureFormat::Undefined,
|
||||
depth_attachment ? depth_attachment->GetFormat() : AbstractTextureFormat::Undefined,
|
||||
width, height, layers, samples),
|
||||
m_color_attachment(color_attachment), m_depth_attachment(depth_attachment), m_fb(fb),
|
||||
m_load_render_pass(load_render_pass), m_discard_render_pass(discard_render_pass),
|
||||
m_clear_render_pass(clear_render_pass)
|
||||
{
|
||||
}
|
||||
|
||||
VKFramebuffer::~VKFramebuffer()
|
||||
{
|
||||
g_command_buffer_mgr->DeferFramebufferDestruction(m_fb);
|
||||
}
|
||||
|
||||
std::unique_ptr<VKFramebuffer> VKFramebuffer::Create(const VKTexture* color_attachment,
|
||||
const VKTexture* depth_attachment)
|
||||
{
|
||||
if (!ValidateConfig(color_attachment, depth_attachment))
|
||||
return nullptr;
|
||||
|
||||
const VkFormat vk_color_format =
|
||||
color_attachment ? color_attachment->GetRawTexIdentifier()->GetFormat() : VK_FORMAT_UNDEFINED;
|
||||
const VkFormat vk_depth_format =
|
||||
depth_attachment ? depth_attachment->GetRawTexIdentifier()->GetFormat() : VK_FORMAT_UNDEFINED;
|
||||
const VKTexture* either_attachment = color_attachment ? color_attachment : depth_attachment;
|
||||
const u32 width = either_attachment->GetWidth();
|
||||
const u32 height = either_attachment->GetHeight();
|
||||
const u32 layers = either_attachment->GetLayers();
|
||||
const u32 samples = either_attachment->GetSamples();
|
||||
|
||||
std::array<VkImageView, 2> attachment_views{};
|
||||
u32 num_attachments = 0;
|
||||
|
||||
if (color_attachment)
|
||||
attachment_views[num_attachments++] = color_attachment->GetRawTexIdentifier()->GetView();
|
||||
|
||||
if (depth_attachment)
|
||||
attachment_views[num_attachments++] = depth_attachment->GetRawTexIdentifier()->GetView();
|
||||
|
||||
VkRenderPass load_render_pass = g_object_cache->GetRenderPass(
|
||||
vk_color_format, vk_depth_format, samples, VK_ATTACHMENT_LOAD_OP_LOAD);
|
||||
VkRenderPass discard_render_pass = g_object_cache->GetRenderPass(
|
||||
vk_color_format, vk_depth_format, samples, VK_ATTACHMENT_LOAD_OP_DONT_CARE);
|
||||
VkRenderPass clear_render_pass = g_object_cache->GetRenderPass(
|
||||
vk_color_format, vk_depth_format, samples, VK_ATTACHMENT_LOAD_OP_CLEAR);
|
||||
if (load_render_pass == VK_NULL_HANDLE || discard_render_pass == VK_NULL_HANDLE ||
|
||||
clear_render_pass == VK_NULL_HANDLE)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
VkFramebufferCreateInfo framebuffer_info = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
||||
nullptr,
|
||||
0,
|
||||
load_render_pass,
|
||||
num_attachments,
|
||||
attachment_views.data(),
|
||||
width,
|
||||
height,
|
||||
layers};
|
||||
|
||||
VkFramebuffer fb;
|
||||
VkResult res =
|
||||
vkCreateFramebuffer(g_vulkan_context->GetDevice(), &framebuffer_info, nullptr, &fb);
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
LOG_VULKAN_ERROR(res, "vkCreateFramebuffer failed: ");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return std::make_unique<VKFramebuffer>(color_attachment, depth_attachment, width, height, layers,
|
||||
samples, fb, load_render_pass, discard_render_pass,
|
||||
clear_render_pass);
|
||||
}
|
||||
|
||||
void VKFramebuffer::TransitionForRender() const
|
||||
{
|
||||
if (m_color_attachment)
|
||||
{
|
||||
m_color_attachment->GetRawTexIdentifier()->TransitionToLayout(
|
||||
g_command_buffer_mgr->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
}
|
||||
|
||||
if (m_depth_attachment)
|
||||
{
|
||||
m_depth_attachment->GetRawTexIdentifier()->TransitionToLayout(
|
||||
g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
|
||||
}
|
||||
}
|
||||
|
||||
void VKFramebuffer::TransitionForSample() const
|
||||
{
|
||||
if (StateTracker::GetInstance()->GetFramebuffer() == m_fb)
|
||||
StateTracker::GetInstance()->EndRenderPass();
|
||||
|
||||
if (m_color_attachment)
|
||||
{
|
||||
m_color_attachment->GetRawTexIdentifier()->TransitionToLayout(
|
||||
g_command_buffer_mgr->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
}
|
||||
|
||||
if (m_depth_attachment)
|
||||
{
|
||||
m_depth_attachment->GetRawTexIdentifier()->TransitionToLayout(
|
||||
g_command_buffer_mgr->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Vulkan
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <memory>
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
#include "VideoCommon/AbstractFramebuffer.h"
|
||||
#include "VideoCommon/AbstractStagingTexture.h"
|
||||
#include "VideoCommon/AbstractTexture.h"
|
||||
|
||||
@ -28,6 +29,8 @@ public:
|
||||
void ScaleRectangleFromTexture(const AbstractTexture* source,
|
||||
const MathUtil::Rectangle<int>& src_rect,
|
||||
const MathUtil::Rectangle<int>& dst_rect) override;
|
||||
void ResolveFromTexture(const AbstractTexture* src, const MathUtil::Rectangle<int>& rect,
|
||||
u32 layer, u32 level) override;
|
||||
|
||||
void Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer,
|
||||
size_t buffer_size) override;
|
||||
@ -78,4 +81,32 @@ private:
|
||||
VkFence m_flush_fence = VK_NULL_HANDLE;
|
||||
};
|
||||
|
||||
class VKFramebuffer final : public AbstractFramebuffer
|
||||
{
|
||||
public:
|
||||
VKFramebuffer(const VKTexture* color_attachment, const VKTexture* depth_attachment, u32 width,
|
||||
u32 height, u32 layers, u32 samples, VkFramebuffer fb,
|
||||
VkRenderPass load_render_pass, VkRenderPass discard_render_pass,
|
||||
VkRenderPass clear_render_pass);
|
||||
~VKFramebuffer() override;
|
||||
|
||||
VkFramebuffer GetFB() const { return m_fb; }
|
||||
VkRenderPass GetLoadRenderPass() const { return m_load_render_pass; }
|
||||
VkRenderPass GetDiscardRenderPass() const { return m_discard_render_pass; }
|
||||
VkRenderPass GetClearRenderPass() const { return m_clear_render_pass; }
|
||||
void TransitionForRender() const;
|
||||
void TransitionForSample() const;
|
||||
|
||||
static std::unique_ptr<VKFramebuffer> Create(const VKTexture* color_attachments,
|
||||
const VKTexture* depth_attachment);
|
||||
|
||||
protected:
|
||||
const VKTexture* m_color_attachment;
|
||||
const VKTexture* m_depth_attachment;
|
||||
VkFramebuffer m_fb;
|
||||
VkRenderPass m_load_render_pass;
|
||||
VkRenderPass m_discard_render_pass;
|
||||
VkRenderPass m_clear_render_pass;
|
||||
};
|
||||
|
||||
} // namespace Vulkan
|
||||
|
55
Source/Core/VideoCommon/AbstractFramebuffer.cpp
Normal file
55
Source/Core/VideoCommon/AbstractFramebuffer.cpp
Normal file
@ -0,0 +1,55 @@
|
||||
// Copyright 2018 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "VideoCommon/AbstractFramebuffer.h"
|
||||
#include "VideoCommon/AbstractTexture.h"
|
||||
|
||||
AbstractFramebuffer::AbstractFramebuffer(AbstractTextureFormat color_format,
|
||||
AbstractTextureFormat depth_format, u32 width, u32 height,
|
||||
u32 layers, u32 samples)
|
||||
: m_color_format(color_format), m_depth_format(depth_format), m_width(width), m_height(height),
|
||||
m_layers(layers), m_samples(samples)
|
||||
{
|
||||
}
|
||||
|
||||
AbstractFramebuffer::~AbstractFramebuffer() = default;
|
||||
|
||||
bool AbstractFramebuffer::ValidateConfig(const AbstractTexture* color_attachment,
|
||||
const AbstractTexture* depth_attachment)
|
||||
{
|
||||
// Must have at least a color or depth attachment.
|
||||
if (!color_attachment && !depth_attachment)
|
||||
return false;
|
||||
|
||||
// Currently we only expose a single mip level for render target textures.
|
||||
// MSAA textures are not supported with mip levels on most backends, and it simplifies our
|
||||
// handling of framebuffers.
|
||||
auto CheckAttachment = [](const AbstractTexture* tex) {
|
||||
return tex->GetConfig().rendertarget && tex->GetConfig().levels == 1;
|
||||
};
|
||||
if ((color_attachment && !CheckAttachment(color_attachment)) ||
|
||||
depth_attachment && !CheckAttachment(depth_attachment))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// If both color and depth are present, their attributes must match.
|
||||
if (color_attachment && depth_attachment)
|
||||
{
|
||||
if (color_attachment->GetConfig().width != depth_attachment->GetConfig().width ||
|
||||
color_attachment->GetConfig().height != depth_attachment->GetConfig().height ||
|
||||
color_attachment->GetConfig().layers != depth_attachment->GetConfig().layers ||
|
||||
color_attachment->GetConfig().samples != depth_attachment->GetConfig().samples)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
MathUtil::Rectangle<int> AbstractFramebuffer::GetRect() const
|
||||
{
|
||||
return MathUtil::Rectangle<int>(0, 0, static_cast<int>(m_width), static_cast<int>(m_height));
|
||||
}
|
45
Source/Core/VideoCommon/AbstractFramebuffer.h
Normal file
45
Source/Core/VideoCommon/AbstractFramebuffer.h
Normal file
@ -0,0 +1,45 @@
|
||||
// Copyright 2018 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/MathUtil.h"
|
||||
#include "VideoCommon/TextureConfig.h"
|
||||
|
||||
class AbstractTexture;
|
||||
|
||||
// An abstract framebuffer wraps a backend framebuffer/view object, which can be used to
|
||||
// draw onto a texture. Currently, only single-level textures are supported. Multi-layer
|
||||
// textures will render by default only to the first layer, however, multiple layers
|
||||
// be rendered in parallel using geometry shaders and layer variable.
|
||||
|
||||
class AbstractFramebuffer
|
||||
{
|
||||
public:
|
||||
AbstractFramebuffer(AbstractTextureFormat color_format, AbstractTextureFormat depth_format,
|
||||
u32 width, u32 height, u32 layers, u32 samples);
|
||||
virtual ~AbstractFramebuffer();
|
||||
|
||||
static bool ValidateConfig(const AbstractTexture* color_attachment,
|
||||
const AbstractTexture* depth_attachment);
|
||||
|
||||
AbstractTextureFormat GetColorFormat() const { return m_color_format; }
|
||||
AbstractTextureFormat GetDepthFormat() const { return m_depth_format; }
|
||||
bool HasColorBuffer() const { return m_color_format != AbstractTextureFormat::Undefined; }
|
||||
bool HasDepthBuffer() const { return m_depth_format != AbstractTextureFormat::Undefined; }
|
||||
u32 GetWidth() const { return m_width; }
|
||||
u32 GetHeight() const { return m_height; }
|
||||
u32 GetLayers() const { return m_layers; }
|
||||
u32 GetSamples() const { return m_samples; }
|
||||
MathUtil::Rectangle<int> GetRect() const;
|
||||
|
||||
protected:
|
||||
AbstractTextureFormat m_color_format;
|
||||
AbstractTextureFormat m_depth_format;
|
||||
u32 m_width;
|
||||
u32 m_height;
|
||||
u32 m_layers;
|
||||
u32 m_samples;
|
||||
};
|
@ -29,7 +29,7 @@ bool AbstractTexture::Save(const std::string& filename, unsigned int level)
|
||||
|
||||
// Use a temporary staging texture for the download. Certainly not optimal,
|
||||
// but this is not a frequently-executed code path..
|
||||
TextureConfig readback_texture_config(level_width, level_height, 1, 1,
|
||||
TextureConfig readback_texture_config(level_width, level_height, 1, 1, 1,
|
||||
AbstractTextureFormat::RGBA8, false);
|
||||
auto readback_texture =
|
||||
g_renderer->CreateStagingTexture(StagingTextureType::Readback, readback_texture_config);
|
||||
@ -64,6 +64,25 @@ bool AbstractTexture::IsCompressedFormat(AbstractTextureFormat format)
|
||||
}
|
||||
}
|
||||
|
||||
bool AbstractTexture::IsDepthFormat(AbstractTextureFormat format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case AbstractTextureFormat::D16:
|
||||
case AbstractTextureFormat::D32F:
|
||||
case AbstractTextureFormat::D32F_S8:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool AbstractTexture::IsStencilFormat(AbstractTextureFormat format)
|
||||
{
|
||||
return format == AbstractTextureFormat::D32F_S8;
|
||||
}
|
||||
|
||||
size_t AbstractTexture::CalculateStrideForFormat(AbstractTextureFormat format, u32 row_length)
|
||||
{
|
||||
switch (format)
|
||||
@ -74,9 +93,16 @@ size_t AbstractTexture::CalculateStrideForFormat(AbstractTextureFormat format, u
|
||||
case AbstractTextureFormat::DXT5:
|
||||
case AbstractTextureFormat::BPTC:
|
||||
return static_cast<size_t>(std::max(1u, row_length / 4)) * 16;
|
||||
case AbstractTextureFormat::R16:
|
||||
case AbstractTextureFormat::D16:
|
||||
return static_cast<size_t>(row_length) * 2;
|
||||
case AbstractTextureFormat::RGBA8:
|
||||
case AbstractTextureFormat::BGRA8:
|
||||
case AbstractTextureFormat::R32F:
|
||||
case AbstractTextureFormat::D32F:
|
||||
return static_cast<size_t>(row_length) * 4;
|
||||
case AbstractTextureFormat::D32F_S8:
|
||||
return static_cast<size_t>(row_length) * 8;
|
||||
default:
|
||||
PanicAlert("Unhandled texture format.");
|
||||
return 0;
|
||||
@ -93,9 +119,16 @@ size_t AbstractTexture::GetTexelSizeForFormat(AbstractTextureFormat format)
|
||||
case AbstractTextureFormat::DXT5:
|
||||
case AbstractTextureFormat::BPTC:
|
||||
return 16;
|
||||
case AbstractTextureFormat::R16:
|
||||
case AbstractTextureFormat::D16:
|
||||
return 2;
|
||||
case AbstractTextureFormat::RGBA8:
|
||||
case AbstractTextureFormat::BGRA8:
|
||||
case AbstractTextureFormat::R32F:
|
||||
case AbstractTextureFormat::D32F:
|
||||
return 4;
|
||||
case AbstractTextureFormat::D32F_S8:
|
||||
return 8;
|
||||
default:
|
||||
PanicAlert("Unhandled texture format.");
|
||||
return 0;
|
||||
|
@ -24,12 +24,23 @@ public:
|
||||
virtual void ScaleRectangleFromTexture(const AbstractTexture* source,
|
||||
const MathUtil::Rectangle<int>& srcrect,
|
||||
const MathUtil::Rectangle<int>& dstrect) = 0;
|
||||
virtual void ResolveFromTexture(const AbstractTexture* src, const MathUtil::Rectangle<int>& rect,
|
||||
u32 layer, u32 level) = 0;
|
||||
virtual void Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer,
|
||||
size_t buffer_size) = 0;
|
||||
|
||||
u32 GetWidth() const { return m_config.width; }
|
||||
u32 GetHeight() const { return m_config.height; }
|
||||
u32 GetLevels() const { return m_config.levels; }
|
||||
u32 GetLayers() const { return m_config.layers; }
|
||||
u32 GetSamples() const { return m_config.samples; }
|
||||
AbstractTextureFormat GetFormat() const { return m_config.format; }
|
||||
bool IsMultisampled() const { return m_config.IsMultisampled(); }
|
||||
bool Save(const std::string& filename, unsigned int level);
|
||||
|
||||
static bool IsCompressedFormat(AbstractTextureFormat format);
|
||||
static bool IsDepthFormat(AbstractTextureFormat format);
|
||||
static bool IsStencilFormat(AbstractTextureFormat format);
|
||||
static size_t CalculateStrideForFormat(AbstractTextureFormat format, u32 row_length);
|
||||
static size_t GetTexelSizeForFormat(AbstractTextureFormat format);
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
set(SRCS
|
||||
AbstractFramebuffer.cpp
|
||||
AbstractStagingTexture.cpp
|
||||
AbstractTexture.cpp
|
||||
AsyncRequests.cpp
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include "Core/Movie.h"
|
||||
|
||||
#include "VideoCommon/AVIDump.h"
|
||||
#include "VideoCommon/AbstractFramebuffer.h"
|
||||
#include "VideoCommon/AbstractStagingTexture.h"
|
||||
#include "VideoCommon/AbstractTexture.h"
|
||||
#include "VideoCommon/BPMemory.h"
|
||||
@ -739,7 +740,7 @@ void Renderer::RenderFrameDump()
|
||||
m_frame_dump_render_texture->GetConfig().height == static_cast<u32>(target_height))
|
||||
{
|
||||
// Recreate texture objects. Release before creating so we don't temporarily use twice the RAM.
|
||||
TextureConfig config(target_width, target_height, 1, 1, AbstractTextureFormat::RGBA8, true);
|
||||
TextureConfig config(target_width, target_height, 1, 1, 1, AbstractTextureFormat::RGBA8, true);
|
||||
m_frame_dump_render_texture.reset();
|
||||
m_frame_dump_render_texture = CreateTexture(config);
|
||||
_assert_(m_frame_dump_render_texture);
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <condition_variable>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
@ -32,7 +33,7 @@
|
||||
#include "VideoCommon/RenderState.h"
|
||||
#include "VideoCommon/VideoCommon.h"
|
||||
|
||||
class AbstractRawTexture;
|
||||
class AbstractFramebuffer;
|
||||
class AbstractPipeline;
|
||||
class AbstractShader;
|
||||
class AbstractTexture;
|
||||
@ -64,6 +65,8 @@ public:
|
||||
Renderer(int backbuffer_width, int backbuffer_height);
|
||||
virtual ~Renderer();
|
||||
|
||||
using ClearColor = std::array<float, 4>;
|
||||
|
||||
enum PixelPerfQuery
|
||||
{
|
||||
PP_ZCOMP_INPUT_ZCOMPLOC,
|
||||
@ -96,6 +99,17 @@ public:
|
||||
virtual std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config) = 0;
|
||||
virtual std::unique_ptr<AbstractStagingTexture>
|
||||
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) = 0;
|
||||
virtual std::unique_ptr<AbstractFramebuffer>
|
||||
CreateFramebuffer(const AbstractTexture* color_attachment,
|
||||
const AbstractTexture* depth_attachment) = 0;
|
||||
|
||||
// Framebuffer operations.
|
||||
virtual void SetFramebuffer(const AbstractFramebuffer* framebuffer) {}
|
||||
virtual void SetAndDiscardFramebuffer(const AbstractFramebuffer* framebuffer) {}
|
||||
virtual void SetAndClearFramebuffer(const AbstractFramebuffer* framebuffer,
|
||||
const ClearColor& color_value = {}, float depth_value = 0.0f)
|
||||
{
|
||||
}
|
||||
|
||||
// Shader modules/objects.
|
||||
virtual std::unique_ptr<AbstractShader>
|
||||
@ -105,6 +119,9 @@ public:
|
||||
virtual std::unique_ptr<AbstractPipeline>
|
||||
CreatePipeline(const AbstractPipelineConfig& config) = 0;
|
||||
|
||||
const AbstractFramebuffer* GetCurrentFramebuffer() const { return m_current_framebuffer; }
|
||||
u32 GetCurrentFramebufferWidth() const { return m_current_framebuffer_width; }
|
||||
u32 GetCurrentFramebufferHeight() const { return m_current_framebuffer_height; }
|
||||
// Ideal internal resolution - multiple of the native EFB resolution
|
||||
int GetTargetWidth() const { return m_target_width; }
|
||||
int GetTargetHeight() const { return m_target_height; }
|
||||
@ -193,6 +210,11 @@ protected:
|
||||
void CheckFifoRecording();
|
||||
void RecordVideoMemory();
|
||||
|
||||
// TODO: Remove the width/height parameters once we make the EFB an abstract framebuffer.
|
||||
const AbstractFramebuffer* m_current_framebuffer = nullptr;
|
||||
u32 m_current_framebuffer_width = 1;
|
||||
u32 m_current_framebuffer_height = 1;
|
||||
|
||||
Common::Flag m_screenshot_request;
|
||||
Common::Event m_screenshot_completed;
|
||||
std::mutex m_screenshot_lock;
|
||||
|
@ -9,8 +9,8 @@
|
||||
|
||||
bool TextureConfig::operator==(const TextureConfig& o) const
|
||||
{
|
||||
return std::tie(width, height, levels, layers, format, rendertarget) ==
|
||||
std::tie(o.width, o.height, o.levels, o.layers, o.format, o.rendertarget);
|
||||
return std::tie(width, height, levels, layers, samples, format, rendertarget) ==
|
||||
std::tie(o.width, o.height, o.levels, o.layers, o.samples, o.format, o.rendertarget);
|
||||
}
|
||||
|
||||
bool TextureConfig::operator!=(const TextureConfig& o) const
|
||||
@ -38,3 +38,8 @@ size_t TextureConfig::GetMipStride(u32 level) const
|
||||
{
|
||||
return AbstractTexture::CalculateStrideForFormat(format, std::max(width >> level, 1u));
|
||||
}
|
||||
|
||||
bool TextureConfig::IsMultisampled() const
|
||||
{
|
||||
return samples > 1;
|
||||
}
|
||||
|
@ -18,6 +18,11 @@ enum class AbstractTextureFormat : u32
|
||||
DXT3,
|
||||
DXT5,
|
||||
BPTC,
|
||||
R16,
|
||||
D16,
|
||||
R32F,
|
||||
D32F,
|
||||
D32F_S8,
|
||||
Undefined
|
||||
};
|
||||
|
||||
@ -31,10 +36,10 @@ enum class StagingTextureType
|
||||
struct TextureConfig
|
||||
{
|
||||
constexpr TextureConfig() = default;
|
||||
constexpr TextureConfig(u32 width_, u32 height_, u32 levels_, u32 layers_,
|
||||
constexpr TextureConfig(u32 width_, u32 height_, u32 levels_, u32 layers_, u32 samples_,
|
||||
AbstractTextureFormat format_, bool rendertarget_)
|
||||
: width(width_), height(height_), levels(levels_), layers(layers_), format(format_),
|
||||
rendertarget(rendertarget_)
|
||||
: width(width_), height(height_), levels(levels_), layers(layers_), samples(samples_),
|
||||
format(format_), rendertarget(rendertarget_)
|
||||
{
|
||||
}
|
||||
|
||||
@ -44,11 +49,13 @@ struct TextureConfig
|
||||
MathUtil::Rectangle<int> GetMipRect(u32 level) const;
|
||||
size_t GetStride() const;
|
||||
size_t GetMipStride(u32 level) const;
|
||||
bool IsMultisampled() const;
|
||||
|
||||
u32 width = 0;
|
||||
u32 height = 0;
|
||||
u32 levels = 1;
|
||||
u32 layers = 1;
|
||||
u32 samples = 1;
|
||||
AbstractTextureFormat format = AbstractTextureFormat::RGBA8;
|
||||
bool rendertarget = false;
|
||||
};
|
||||
|
@ -36,6 +36,7 @@
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<ItemGroup>
|
||||
<ClCompile Include="AbstractFramebuffer.cpp" />
|
||||
<ClCompile Include="AbstractStagingTexture.cpp" />
|
||||
<ClCompile Include="AbstractTexture.cpp" />
|
||||
<ClCompile Include="AsyncRequests.cpp" />
|
||||
@ -98,6 +99,7 @@
|
||||
<ClCompile Include="XFStructs.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="AbstractFramebuffer.h" />
|
||||
<ClInclude Include="AbstractStagingTexture.h" />
|
||||
<ClInclude Include="AbstractPipeline.h" />
|
||||
<ClInclude Include="AbstractShader.h" />
|
||||
|
@ -176,9 +176,6 @@
|
||||
<ClCompile Include="AbstractTexture.cpp">
|
||||
<Filter>Base</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="AbstractRawTexture.cpp">
|
||||
<Filter>Base</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ShaderGenCommon.cpp">
|
||||
<Filter>Shader Generators</Filter>
|
||||
</ClCompile>
|
||||
@ -197,6 +194,9 @@
|
||||
<ClCompile Include="AbstractStagingTexture.cpp">
|
||||
<Filter>Base</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="AbstractFramebuffer.cpp">
|
||||
<Filter>Base</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="CommandProcessor.h" />
|
||||
@ -266,9 +266,6 @@
|
||||
<ClInclude Include="TextureConversionShader.h">
|
||||
<Filter>Shader Generators</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="TextureConvertionShaderGen.h">
|
||||
<Filter>Shader Generators</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="VertexShaderGen.h">
|
||||
<Filter>Shader Generators</Filter>
|
||||
</ClInclude>
|
||||
@ -356,9 +353,6 @@
|
||||
<ClInclude Include="AbstractTexture.h">
|
||||
<Filter>Base</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="AbstractRawTexture.h">
|
||||
<Filter>Base</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="AsyncShaderCompiler.h">
|
||||
<Filter>Util</Filter>
|
||||
</ClInclude>
|
||||
@ -380,6 +374,10 @@
|
||||
<ClInclude Include="AbstractPipeline.h">
|
||||
<Filter>Base</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="TextureConverterShaderGen.h" />
|
||||
<ClInclude Include="AbstractFramebuffer.h">
|
||||
<Filter>Base</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="CMakeLists.txt" />
|
||||
|
Loading…
x
Reference in New Issue
Block a user