VideoCommon: Add support for Abstract Framebuffers

This commit is contained in:
Stenzek 2018-01-21 20:22:45 +10:00
parent 2a6d9e4713
commit 4c24a69710
31 changed files with 792 additions and 9 deletions

View File

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

View File

@ -4,8 +4,10 @@
#pragma once
#include <memory>
#include "Common/CommonTypes.h"
#include "VideoCommon/AbstractFramebuffer.h"
#include "VideoCommon/AbstractStagingTexture.h"
#include "VideoCommon/AbstractTexture.h"
@ -63,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

View File

@ -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,
@ -648,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();
@ -763,6 +776,9 @@ 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();
@ -792,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;

View File

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

View File

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

View File

@ -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"
@ -53,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

View File

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

View File

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

View File

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

View File

@ -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"
@ -74,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

View File

@ -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(),
@ -1496,6 +1547,9 @@ 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.

View File

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

View File

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

View File

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

View File

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

View File

@ -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"
@ -59,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

View File

@ -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()
@ -1037,12 +1053,78 @@ 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);

View File

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

View File

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

View File

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

View File

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

View File

@ -7,6 +7,7 @@
#include <memory>
#include <vulkan/vulkan.h>
#include "VideoCommon/AbstractFramebuffer.h"
#include "VideoCommon/AbstractStagingTexture.h"
#include "VideoCommon/AbstractTexture.h"
@ -80,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

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

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

View File

@ -78,6 +78,11 @@ bool AbstractTexture::IsDepthFormat(AbstractTextureFormat format)
}
}
bool AbstractTexture::IsStencilFormat(AbstractTextureFormat format)
{
return format == AbstractTextureFormat::D32F_S8;
}
size_t AbstractTexture::CalculateStrideForFormat(AbstractTextureFormat format, u32 row_length)
{
switch (format)

View File

@ -40,6 +40,7 @@ public:
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);

View File

@ -1,4 +1,5 @@
set(SRCS
AbstractFramebuffer.cpp
AbstractStagingTexture.cpp
AbstractTexture.cpp
AsyncRequests.cpp

View File

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

View File

@ -14,6 +14,7 @@
#pragma once
#include <array>
#include <condition_variable>
#include <memory>
#include <mutex>
@ -32,6 +33,7 @@
#include "VideoCommon/RenderState.h"
#include "VideoCommon/VideoCommon.h"
class AbstractFramebuffer;
class AbstractPipeline;
class AbstractShader;
class AbstractTexture;
@ -63,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,
@ -95,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>
@ -104,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; }
@ -192,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;

View File

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

View File

@ -194,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" />
@ -263,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>
@ -374,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" />