GPUDevice: Add support for Raster Ordered Views
This commit is contained in:
parent
e743c5d1b1
commit
1006fa00da
|
@ -80,8 +80,8 @@ bool D3D11Device::CreateDevice(std::string_view adapter, bool threaded_presentat
|
||||||
ComPtr<IDXGIAdapter1> dxgi_adapter = D3DCommon::GetAdapterByName(m_dxgi_factory.Get(), adapter);
|
ComPtr<IDXGIAdapter1> dxgi_adapter = D3DCommon::GetAdapterByName(m_dxgi_factory.Get(), adapter);
|
||||||
m_max_feature_level = D3DCommon::GetDeviceMaxFeatureLevel(dxgi_adapter.Get());
|
m_max_feature_level = D3DCommon::GetDeviceMaxFeatureLevel(dxgi_adapter.Get());
|
||||||
|
|
||||||
static constexpr std::array<D3D_FEATURE_LEVEL, 3> requested_feature_levels = {
|
static constexpr std::array<D3D_FEATURE_LEVEL, 4> requested_feature_levels = {
|
||||||
{D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0}};
|
{D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0}};
|
||||||
|
|
||||||
ComPtr<ID3D11Device> temp_device;
|
ComPtr<ID3D11Device> temp_device;
|
||||||
ComPtr<ID3D11DeviceContext> temp_context;
|
ComPtr<ID3D11DeviceContext> temp_context;
|
||||||
|
@ -194,6 +194,14 @@ void D3D11Device::SetFeatures(FeatureMask disabled_features)
|
||||||
m_features.shader_cache = true;
|
m_features.shader_cache = true;
|
||||||
m_features.pipeline_cache = false;
|
m_features.pipeline_cache = false;
|
||||||
m_features.prefer_unused_textures = false;
|
m_features.prefer_unused_textures = false;
|
||||||
|
m_features.raster_order_views = false;
|
||||||
|
if (!(disabled_features & FEATURE_MASK_RASTER_ORDER_VIEWS))
|
||||||
|
{
|
||||||
|
D3D11_FEATURE_DATA_D3D11_OPTIONS2 data = {};
|
||||||
|
m_features.raster_order_views =
|
||||||
|
(SUCCEEDED(m_device->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS2, &data, sizeof(data))) &&
|
||||||
|
data.ROVsSupported);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 D3D11Device::GetSwapChainBufferCount() const
|
u32 D3D11Device::GetSwapChainBufferCount() const
|
||||||
|
@ -567,12 +575,15 @@ void D3D11Device::ResolveTextureRegion(GPUTexture* dst, u32 dst_x, u32 dst_y, u3
|
||||||
src11->GetD3DTexture(), 0, dst11->GetDXGIFormat());
|
src11->GetD3DTexture(), 0, dst11->GetDXGIFormat());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool D3D11Device::IsRenderTargetBound(const GPUTexture* tex) const
|
bool D3D11Device::IsRenderTargetBound(const D3D11Texture* tex) const
|
||||||
{
|
{
|
||||||
for (u32 i = 0; i < m_num_current_render_targets; i++)
|
if (tex->IsRenderTarget() || tex->IsRWTexture())
|
||||||
{
|
{
|
||||||
if (m_current_render_targets[i] == tex)
|
for (u32 i = 0; i < m_num_current_render_targets; i++)
|
||||||
return true;
|
{
|
||||||
|
if (m_current_render_targets[i] == tex)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -580,23 +591,26 @@ bool D3D11Device::IsRenderTargetBound(const GPUTexture* tex) const
|
||||||
|
|
||||||
void D3D11Device::ClearRenderTarget(GPUTexture* t, u32 c)
|
void D3D11Device::ClearRenderTarget(GPUTexture* t, u32 c)
|
||||||
{
|
{
|
||||||
GPUDevice::ClearRenderTarget(t, c);
|
D3D11Texture* const T = static_cast<D3D11Texture*>(t);
|
||||||
if (IsRenderTargetBound(t))
|
GPUDevice::ClearRenderTarget(T, c);
|
||||||
static_cast<D3D11Texture*>(t)->CommitClear(m_context.Get());
|
if (IsRenderTargetBound(T))
|
||||||
|
T->CommitClear(m_context.Get());
|
||||||
}
|
}
|
||||||
|
|
||||||
void D3D11Device::ClearDepth(GPUTexture* t, float d)
|
void D3D11Device::ClearDepth(GPUTexture* t, float d)
|
||||||
{
|
{
|
||||||
GPUDevice::ClearDepth(t, d);
|
D3D11Texture* const T = static_cast<D3D11Texture*>(t);
|
||||||
if (m_current_depth_target == t)
|
GPUDevice::ClearDepth(T, d);
|
||||||
static_cast<D3D11Texture*>(t)->CommitClear(m_context.Get());
|
if (T == m_current_depth_target)
|
||||||
|
T->CommitClear(m_context.Get());
|
||||||
}
|
}
|
||||||
|
|
||||||
void D3D11Device::InvalidateRenderTarget(GPUTexture* t)
|
void D3D11Device::InvalidateRenderTarget(GPUTexture* t)
|
||||||
{
|
{
|
||||||
GPUDevice::InvalidateRenderTarget(t);
|
D3D11Texture* const T = static_cast<D3D11Texture*>(t);
|
||||||
if (t->IsRenderTarget() ? IsRenderTargetBound(t) : (m_current_depth_target == t))
|
GPUDevice::InvalidateRenderTarget(T);
|
||||||
static_cast<D3D11Texture*>(t)->CommitClear(m_context.Get());
|
if (T->IsDepthStencil() ? (m_current_depth_target == T) : IsRenderTargetBound(T))
|
||||||
|
T->CommitClear(m_context.Get());
|
||||||
}
|
}
|
||||||
|
|
||||||
void D3D11Device::SetVSyncMode(GPUVSyncMode mode, bool allow_present_throttle)
|
void D3D11Device::SetVSyncMode(GPUVSyncMode mode, bool allow_present_throttle)
|
||||||
|
@ -662,6 +676,7 @@ bool D3D11Device::BeginPresent(bool skip_present)
|
||||||
m_context->OMSetRenderTargets(1, m_swap_chain_rtv.GetAddressOf(), nullptr);
|
m_context->OMSetRenderTargets(1, m_swap_chain_rtv.GetAddressOf(), nullptr);
|
||||||
s_stats.num_render_passes++;
|
s_stats.num_render_passes++;
|
||||||
m_num_current_render_targets = 0;
|
m_num_current_render_targets = 0;
|
||||||
|
m_current_render_pass_flags = GPUPipeline::NoRenderPassFlags;
|
||||||
std::memset(m_current_render_targets.data(), 0, sizeof(m_current_render_targets));
|
std::memset(m_current_render_targets.data(), 0, sizeof(m_current_render_targets));
|
||||||
m_current_depth_target = nullptr;
|
m_current_depth_target = nullptr;
|
||||||
return true;
|
return true;
|
||||||
|
@ -934,15 +949,20 @@ void D3D11Device::UnmapUniformBuffer(u32 size)
|
||||||
}
|
}
|
||||||
|
|
||||||
void D3D11Device::SetRenderTargets(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds,
|
void D3D11Device::SetRenderTargets(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds,
|
||||||
GPUPipeline::RenderPassFlag feedback_loop)
|
GPUPipeline::RenderPassFlag flags)
|
||||||
{
|
{
|
||||||
ID3D11RenderTargetView* rtvs[MAX_RENDER_TARGETS];
|
DebugAssert(
|
||||||
DebugAssert(!feedback_loop);
|
!(flags & (GPUPipeline::RenderPassFlag::ColorFeedbackLoop | GPUPipeline::RenderPassFlag::SampleDepthBuffer)));
|
||||||
|
|
||||||
bool changed = (m_num_current_render_targets != num_rts || m_current_depth_target != ds);
|
// Make sure DSV isn't bound.
|
||||||
m_current_depth_target = static_cast<D3D11Texture*>(ds);
|
D3D11Texture* DS = static_cast<D3D11Texture*>(ds);
|
||||||
|
if (DS)
|
||||||
|
DS->CommitClear(m_context.Get());
|
||||||
|
|
||||||
// Make sure textures aren't bound.
|
bool changed =
|
||||||
|
(m_num_current_render_targets != num_rts || m_current_depth_target != DS || m_current_render_pass_flags != flags);
|
||||||
|
m_current_render_pass_flags = flags;
|
||||||
|
m_current_depth_target = DS;
|
||||||
if (ds)
|
if (ds)
|
||||||
{
|
{
|
||||||
const ID3D11ShaderResourceView* srv = static_cast<D3D11Texture*>(ds)->GetD3DSRV();
|
const ID3D11ShaderResourceView* srv = static_cast<D3D11Texture*>(ds)->GetD3DSRV();
|
||||||
|
@ -958,13 +978,12 @@ void D3D11Device::SetRenderTargets(GPUTexture* const* rts, u32 num_rts, GPUTextu
|
||||||
|
|
||||||
for (u32 i = 0; i < num_rts; i++)
|
for (u32 i = 0; i < num_rts; i++)
|
||||||
{
|
{
|
||||||
D3D11Texture* const dt = static_cast<D3D11Texture*>(rts[i]);
|
D3D11Texture* const RT = static_cast<D3D11Texture*>(rts[i]);
|
||||||
changed |= m_current_render_targets[i] != dt;
|
changed |= m_current_render_targets[i] != RT;
|
||||||
m_current_render_targets[i] = dt;
|
m_current_render_targets[i] = RT;
|
||||||
rtvs[i] = dt->GetD3DRTV();
|
RT->CommitClear(m_context.Get());
|
||||||
dt->CommitClear(m_context.Get());
|
|
||||||
|
|
||||||
const ID3D11ShaderResourceView* srv = dt->GetD3DSRV();
|
const ID3D11ShaderResourceView* srv = RT->GetD3DSRV();
|
||||||
for (u32 j = 0; j < MAX_TEXTURE_SAMPLERS; j++)
|
for (u32 j = 0; j < MAX_TEXTURE_SAMPLERS; j++)
|
||||||
{
|
{
|
||||||
if (m_current_textures[j] && m_current_textures[j] == srv)
|
if (m_current_textures[j] && m_current_textures[j] == srv)
|
||||||
|
@ -981,7 +1000,27 @@ void D3D11Device::SetRenderTargets(GPUTexture* const* rts, u32 num_rts, GPUTextu
|
||||||
return;
|
return;
|
||||||
|
|
||||||
s_stats.num_render_passes++;
|
s_stats.num_render_passes++;
|
||||||
m_context->OMSetRenderTargets(num_rts, rtvs, ds ? static_cast<D3D11Texture*>(ds)->GetD3DDSV() : nullptr);
|
|
||||||
|
if (m_current_render_pass_flags & GPUPipeline::BindRenderTargetsAsImages)
|
||||||
|
{
|
||||||
|
std::array<ID3D11UnorderedAccessView*, MAX_RENDER_TARGETS> uavs;
|
||||||
|
for (u32 i = 0; i < m_num_current_render_targets; i++)
|
||||||
|
uavs[i] = m_current_render_targets[i]->GetD3DUAV();
|
||||||
|
|
||||||
|
m_context->OMSetRenderTargetsAndUnorderedAccessViews(
|
||||||
|
0, nullptr, m_current_depth_target ? m_current_depth_target->GetD3DDSV() : nullptr, 0,
|
||||||
|
m_num_current_render_targets, uavs.data(), nullptr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::array<ID3D11RenderTargetView*, MAX_RENDER_TARGETS> rtvs;
|
||||||
|
for (u32 i = 0; i < m_num_current_render_targets; i++)
|
||||||
|
rtvs[i] = m_current_render_targets[i]->GetD3DRTV();
|
||||||
|
|
||||||
|
m_context->OMSetRenderTargets(m_num_current_render_targets,
|
||||||
|
(m_num_current_render_targets > 0) ? rtvs.data() : nullptr,
|
||||||
|
m_current_depth_target ? m_current_depth_target->GetD3DDSV() : nullptr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void D3D11Device::SetTextureSampler(u32 slot, GPUTexture* texture, GPUSampler* sampler)
|
void D3D11Device::SetTextureSampler(u32 slot, GPUTexture* texture, GPUSampler* sampler)
|
||||||
|
@ -1000,7 +1039,11 @@ void D3D11Device::SetTextureSampler(u32 slot, GPUTexture* texture, GPUSampler* s
|
||||||
ID3D11SamplerState* S = sampler ? static_cast<D3D11Sampler*>(sampler)->GetSamplerState() : nullptr;
|
ID3D11SamplerState* S = sampler ? static_cast<D3D11Sampler*>(sampler)->GetSamplerState() : nullptr;
|
||||||
|
|
||||||
// Runtime will null these if we don't...
|
// Runtime will null these if we don't...
|
||||||
DebugAssert(!texture || !IsRenderTargetBound(texture) || m_current_depth_target != texture);
|
DebugAssert(!texture ||
|
||||||
|
!((texture->IsRenderTarget() || texture->IsRWTexture()) &&
|
||||||
|
IsRenderTargetBound(static_cast<D3D11Texture*>(texture))) ||
|
||||||
|
!(texture->IsDepthStencil() &&
|
||||||
|
(!m_current_depth_target || m_current_depth_target != static_cast<D3D11Texture*>(texture))));
|
||||||
|
|
||||||
if (m_current_textures[slot] != T)
|
if (m_current_textures[slot] != T)
|
||||||
{
|
{
|
||||||
|
@ -1038,7 +1081,7 @@ void D3D11Device::UnbindTexture(D3D11Texture* tex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tex->IsRenderTarget())
|
if (tex->IsRenderTarget() || tex->IsRWTexture())
|
||||||
{
|
{
|
||||||
for (u32 i = 0; i < m_num_current_render_targets; i++)
|
for (u32 i = 0; i < m_num_current_render_targets; i++)
|
||||||
{
|
{
|
||||||
|
@ -1050,7 +1093,7 @@ void D3D11Device::UnbindTexture(D3D11Texture* tex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (m_current_depth_target == tex)
|
else if (tex->IsDepthStencil() && m_current_depth_target == tex)
|
||||||
{
|
{
|
||||||
WARNING_LOG("Unbinding current DS");
|
WARNING_LOG("Unbinding current DS");
|
||||||
SetRenderTargets(nullptr, 0, nullptr);
|
SetRenderTargets(nullptr, 0, nullptr);
|
||||||
|
|
|
@ -89,7 +89,7 @@ public:
|
||||||
void* MapUniformBuffer(u32 size) override;
|
void* MapUniformBuffer(u32 size) override;
|
||||||
void UnmapUniformBuffer(u32 size) override;
|
void UnmapUniformBuffer(u32 size) override;
|
||||||
void SetRenderTargets(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds,
|
void SetRenderTargets(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds,
|
||||||
GPUPipeline::RenderPassFlag feedback_loop = GPUPipeline::NoRenderPassFlags) override;
|
GPUPipeline::RenderPassFlag flags = GPUPipeline::NoRenderPassFlags) override;
|
||||||
void SetPipeline(GPUPipeline* pipeline) override;
|
void SetPipeline(GPUPipeline* pipeline) override;
|
||||||
void SetTextureSampler(u32 slot, GPUTexture* texture, GPUSampler* sampler) override;
|
void SetTextureSampler(u32 slot, GPUTexture* texture, GPUSampler* sampler) override;
|
||||||
void SetTextureBuffer(u32 slot, GPUTextureBuffer* buffer) override;
|
void SetTextureBuffer(u32 slot, GPUTextureBuffer* buffer) override;
|
||||||
|
@ -142,7 +142,7 @@ private:
|
||||||
bool CreateBuffers();
|
bool CreateBuffers();
|
||||||
void DestroyBuffers();
|
void DestroyBuffers();
|
||||||
|
|
||||||
bool IsRenderTargetBound(const GPUTexture* tex) const;
|
bool IsRenderTargetBound(const D3D11Texture* tex) const;
|
||||||
|
|
||||||
ComPtr<ID3D11RasterizerState> GetRasterizationState(const GPUPipeline::RasterizationState& rs, Error* error);
|
ComPtr<ID3D11RasterizerState> GetRasterizationState(const GPUPipeline::RasterizationState& rs, Error* error);
|
||||||
ComPtr<ID3D11DepthStencilState> GetDepthState(const GPUPipeline::DepthState& ds, Error* error);
|
ComPtr<ID3D11DepthStencilState> GetDepthState(const GPUPipeline::DepthState& ds, Error* error);
|
||||||
|
@ -180,6 +180,7 @@ private:
|
||||||
D3D11Pipeline* m_current_pipeline = nullptr;
|
D3D11Pipeline* m_current_pipeline = nullptr;
|
||||||
std::array<D3D11Texture*, MAX_RENDER_TARGETS> m_current_render_targets = {};
|
std::array<D3D11Texture*, MAX_RENDER_TARGETS> m_current_render_targets = {};
|
||||||
u32 m_num_current_render_targets = 0;
|
u32 m_num_current_render_targets = 0;
|
||||||
|
GPUPipeline::RenderPassFlag m_current_render_pass_flags = GPUPipeline::NoRenderPassFlags;
|
||||||
D3D11Texture* m_current_depth_target = nullptr;
|
D3D11Texture* m_current_depth_target = nullptr;
|
||||||
|
|
||||||
ID3D11InputLayout* m_current_input_layout = nullptr;
|
ID3D11InputLayout* m_current_input_layout = nullptr;
|
||||||
|
|
|
@ -95,19 +95,16 @@ std::unique_ptr<GPUSampler> D3D11Device::CreateSampler(const GPUSampler::Config&
|
||||||
|
|
||||||
D3D11Texture::D3D11Texture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, Type type, Format format,
|
D3D11Texture::D3D11Texture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, Type type, Format format,
|
||||||
ComPtr<ID3D11Texture2D> texture, ComPtr<ID3D11ShaderResourceView> srv,
|
ComPtr<ID3D11Texture2D> texture, ComPtr<ID3D11ShaderResourceView> srv,
|
||||||
ComPtr<ID3D11View> rtv_dsv)
|
ComPtr<ID3D11View> rtv_dsv, ComPtr<ID3D11UnorderedAccessView> uav)
|
||||||
: GPUTexture(static_cast<u16>(width), static_cast<u16>(height), static_cast<u8>(layers), static_cast<u8>(levels),
|
: GPUTexture(static_cast<u16>(width), static_cast<u16>(height), static_cast<u8>(layers), static_cast<u8>(levels),
|
||||||
static_cast<u8>(samples), type, format),
|
static_cast<u8>(samples), type, format),
|
||||||
m_texture(std::move(texture)), m_srv(std::move(srv)), m_rtv_dsv(std::move(rtv_dsv))
|
m_texture(std::move(texture)), m_srv(std::move(srv)), m_rtv_dsv(std::move(rtv_dsv)), m_uav(std::move(uav))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
D3D11Texture::~D3D11Texture()
|
D3D11Texture::~D3D11Texture()
|
||||||
{
|
{
|
||||||
D3D11Device::GetInstance().UnbindTexture(this);
|
D3D11Device::GetInstance().UnbindTexture(this);
|
||||||
m_rtv_dsv.Reset();
|
|
||||||
m_srv.Reset();
|
|
||||||
m_texture.Reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
D3D11_TEXTURE2D_DESC D3D11Texture::GetDesc() const
|
D3D11_TEXTURE2D_DESC D3D11Texture::GetDesc() const
|
||||||
|
@ -247,7 +244,7 @@ std::unique_ptr<D3D11Texture> D3D11Texture::Create(ID3D11Device* device, u32 wid
|
||||||
cpu_access = D3D11_CPU_ACCESS_WRITE;
|
cpu_access = D3D11_CPU_ACCESS_WRITE;
|
||||||
break;
|
break;
|
||||||
case Type::RWTexture:
|
case Type::RWTexture:
|
||||||
bind_flags = D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE;
|
bind_flags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -327,8 +324,23 @@ std::unique_ptr<D3D11Texture> D3D11Texture::Create(ID3D11Device* device, u32 wid
|
||||||
rtv_dsv = std::move(dsv);
|
rtv_dsv = std::move(dsv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ComPtr<ID3D11UnorderedAccessView> uav;
|
||||||
|
if (bind_flags & D3D11_BIND_UNORDERED_ACCESS)
|
||||||
|
{
|
||||||
|
const D3D11_UAV_DIMENSION uav_dimension =
|
||||||
|
(desc.ArraySize > 1 ? D3D11_UAV_DIMENSION_TEXTURE2DARRAY : D3D11_UAV_DIMENSION_TEXTURE2D);
|
||||||
|
const CD3D11_UNORDERED_ACCESS_VIEW_DESC uav_desc(uav_dimension, fm.srv_format, 0, 0, desc.ArraySize);
|
||||||
|
const HRESULT hr = device->CreateUnorderedAccessView(texture.Get(), &uav_desc, uav.GetAddressOf());
|
||||||
|
if (FAILED(hr)) [[unlikely]]
|
||||||
|
{
|
||||||
|
ERROR_LOG("Create UAV for texture failed: 0x{:08X}", static_cast<unsigned>(hr));
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return std::unique_ptr<D3D11Texture>(new D3D11Texture(width, height, layers, levels, samples, type, format,
|
return std::unique_ptr<D3D11Texture>(new D3D11Texture(width, height, layers, levels, samples, type, format,
|
||||||
std::move(texture), std::move(srv), std::move(rtv_dsv)));
|
std::move(texture), std::move(srv), std::move(rtv_dsv),
|
||||||
|
std::move(uav)));
|
||||||
}
|
}
|
||||||
|
|
||||||
D3D11TextureBuffer::D3D11TextureBuffer(Format format, u32 size_in_elements) : GPUTextureBuffer(format, size_in_elements)
|
D3D11TextureBuffer::D3D11TextureBuffer(Format format, u32 size_in_elements) : GPUTextureBuffer(format, size_in_elements)
|
||||||
|
|
|
@ -60,6 +60,7 @@ public:
|
||||||
{
|
{
|
||||||
return reinterpret_cast<ID3D11RenderTargetView* const*>(m_rtv_dsv.GetAddressOf());
|
return reinterpret_cast<ID3D11RenderTargetView* const*>(m_rtv_dsv.GetAddressOf());
|
||||||
}
|
}
|
||||||
|
ALWAYS_INLINE ID3D11UnorderedAccessView* GetD3DUAV() const { return m_uav.Get(); }
|
||||||
DXGI_FORMAT GetDXGIFormat() const;
|
DXGI_FORMAT GetDXGIFormat() const;
|
||||||
|
|
||||||
ALWAYS_INLINE operator ID3D11Texture2D*() const { return m_texture.Get(); }
|
ALWAYS_INLINE operator ID3D11Texture2D*() const { return m_texture.Get(); }
|
||||||
|
@ -72,6 +73,7 @@ public:
|
||||||
{
|
{
|
||||||
return static_cast<ID3D11DepthStencilView*>(m_rtv_dsv.Get());
|
return static_cast<ID3D11DepthStencilView*>(m_rtv_dsv.Get());
|
||||||
}
|
}
|
||||||
|
ALWAYS_INLINE operator ID3D11UnorderedAccessView*() const { return m_uav.Get(); }
|
||||||
ALWAYS_INLINE operator bool() const { return static_cast<bool>(m_texture); }
|
ALWAYS_INLINE operator bool() const { return static_cast<bool>(m_texture); }
|
||||||
|
|
||||||
static std::unique_ptr<D3D11Texture> Create(ID3D11Device* device, u32 width, u32 height, u32 layers, u32 levels,
|
static std::unique_ptr<D3D11Texture> Create(ID3D11Device* device, u32 width, u32 height, u32 layers, u32 levels,
|
||||||
|
@ -89,11 +91,13 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
D3D11Texture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, Type type, Format format,
|
D3D11Texture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, Type type, Format format,
|
||||||
ComPtr<ID3D11Texture2D> texture, ComPtr<ID3D11ShaderResourceView> srv, ComPtr<ID3D11View> rtv_dsv);
|
ComPtr<ID3D11Texture2D> texture, ComPtr<ID3D11ShaderResourceView> srv, ComPtr<ID3D11View> rtv_dsv,
|
||||||
|
ComPtr<ID3D11UnorderedAccessView> uav);
|
||||||
|
|
||||||
ComPtr<ID3D11Texture2D> m_texture;
|
ComPtr<ID3D11Texture2D> m_texture;
|
||||||
ComPtr<ID3D11ShaderResourceView> m_srv;
|
ComPtr<ID3D11ShaderResourceView> m_srv;
|
||||||
ComPtr<ID3D11View> m_rtv_dsv;
|
ComPtr<ID3D11View> m_rtv_dsv;
|
||||||
|
ComPtr<ID3D11UnorderedAccessView> m_uav;
|
||||||
u32 m_mapped_subresource = 0;
|
u32 m_mapped_subresource = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -130,7 +130,7 @@ bool D3D12Device::CreateDevice(std::string_view adapter, bool threaded_presentat
|
||||||
|
|
||||||
m_adapter = D3DCommon::GetAdapterByName(m_dxgi_factory.Get(), adapter);
|
m_adapter = D3DCommon::GetAdapterByName(m_dxgi_factory.Get(), adapter);
|
||||||
|
|
||||||
HRESULT hr;
|
HRESULT hr = S_OK;
|
||||||
|
|
||||||
// Enabling the debug layer will fail if the Graphics Tools feature is not installed.
|
// Enabling the debug layer will fail if the Graphics Tools feature is not installed.
|
||||||
if (m_debug_device)
|
if (m_debug_device)
|
||||||
|
@ -149,8 +149,15 @@ bool D3D12Device::CreateDevice(std::string_view adapter, bool threaded_presentat
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the actual device.
|
// Create the actual device.
|
||||||
m_feature_level = D3D_FEATURE_LEVEL_11_0;
|
for (D3D_FEATURE_LEVEL try_feature_level : {D3D_FEATURE_LEVEL_11_0})
|
||||||
hr = D3D12CreateDevice(m_adapter.Get(), m_feature_level, IID_PPV_ARGS(&m_device));
|
{
|
||||||
|
hr = D3D12CreateDevice(m_adapter.Get(), try_feature_level, IID_PPV_ARGS(&m_device));
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
m_feature_level = try_feature_level;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
{
|
{
|
||||||
Error::SetHResult(error, "Failed to create D3D12 device: ", hr);
|
Error::SetHResult(error, "Failed to create D3D12 device: ", hr);
|
||||||
|
@ -479,15 +486,23 @@ bool D3D12Device::CreateDescriptorHeaps(Error* error)
|
||||||
// Allocate null SRV descriptor for unbound textures.
|
// Allocate null SRV descriptor for unbound textures.
|
||||||
static constexpr D3D12_SHADER_RESOURCE_VIEW_DESC null_srv_desc = {
|
static constexpr D3D12_SHADER_RESOURCE_VIEW_DESC null_srv_desc = {
|
||||||
DXGI_FORMAT_R8G8B8A8_UNORM, D3D12_SRV_DIMENSION_TEXTURE2D, D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING, {}};
|
DXGI_FORMAT_R8G8B8A8_UNORM, D3D12_SRV_DIMENSION_TEXTURE2D, D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING, {}};
|
||||||
|
|
||||||
if (!m_descriptor_heap_manager.Allocate(&m_null_srv_descriptor))
|
if (!m_descriptor_heap_manager.Allocate(&m_null_srv_descriptor))
|
||||||
{
|
{
|
||||||
Error::SetStringView(error, "Failed to allocate null SRV descriptor");
|
Error::SetStringView(error, "Failed to allocate null SRV descriptor");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_device->CreateShaderResourceView(nullptr, &null_srv_desc, m_null_srv_descriptor.cpu_handle);
|
m_device->CreateShaderResourceView(nullptr, &null_srv_desc, m_null_srv_descriptor.cpu_handle);
|
||||||
|
|
||||||
|
// Same for UAVs.
|
||||||
|
static constexpr D3D12_UNORDERED_ACCESS_VIEW_DESC null_uav_desc = {
|
||||||
|
DXGI_FORMAT_R8G8B8A8_UNORM, D3D12_UAV_DIMENSION_TEXTURE2D, {}};
|
||||||
|
if (!m_descriptor_heap_manager.Allocate(&m_null_uav_descriptor))
|
||||||
|
{
|
||||||
|
Error::SetStringView(error, "Failed to allocate null UAV descriptor");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_device->CreateUnorderedAccessView(nullptr, nullptr, &null_uav_desc, m_null_uav_descriptor.cpu_handle);
|
||||||
|
|
||||||
// Same for samplers.
|
// Same for samplers.
|
||||||
m_point_sampler = GetSampler(GPUSampler::GetNearestConfig());
|
m_point_sampler = GetSampler(GPUSampler::GetNearestConfig());
|
||||||
for (u32 i = 0; i < MAX_TEXTURE_SAMPLERS; i++)
|
for (u32 i = 0; i < MAX_TEXTURE_SAMPLERS; i++)
|
||||||
|
@ -497,6 +512,8 @@ bool D3D12Device::CreateDescriptorHeaps(Error* error)
|
||||||
|
|
||||||
void D3D12Device::DestroyDescriptorHeaps()
|
void D3D12Device::DestroyDescriptorHeaps()
|
||||||
{
|
{
|
||||||
|
if (m_null_uav_descriptor)
|
||||||
|
m_descriptor_heap_manager.Free(&m_null_uav_descriptor);
|
||||||
if (m_null_srv_descriptor)
|
if (m_null_srv_descriptor)
|
||||||
m_descriptor_heap_manager.Free(&m_null_srv_descriptor);
|
m_descriptor_heap_manager.Free(&m_null_srv_descriptor);
|
||||||
m_sampler_heap_manager.Destroy();
|
m_sampler_heap_manager.Destroy();
|
||||||
|
@ -1248,6 +1265,15 @@ void D3D12Device::SetFeatures(FeatureMask disabled_features)
|
||||||
HRESULT hr = m_dxgi_factory->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allow_tearing_supported,
|
HRESULT hr = m_dxgi_factory->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allow_tearing_supported,
|
||||||
sizeof(allow_tearing_supported));
|
sizeof(allow_tearing_supported));
|
||||||
m_allow_tearing_supported = (SUCCEEDED(hr) && allow_tearing_supported == TRUE);
|
m_allow_tearing_supported = (SUCCEEDED(hr) && allow_tearing_supported == TRUE);
|
||||||
|
|
||||||
|
m_features.raster_order_views = false;
|
||||||
|
if (!(disabled_features & FEATURE_MASK_RASTER_ORDER_VIEWS))
|
||||||
|
{
|
||||||
|
D3D12_FEATURE_DATA_D3D12_OPTIONS options = {};
|
||||||
|
m_features.raster_order_views =
|
||||||
|
SUCCEEDED(m_device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS, &options, sizeof(options))) &&
|
||||||
|
options.ROVsSupported;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void D3D12Device::CopyTextureRegion(GPUTexture* dst, u32 dst_x, u32 dst_y, u32 dst_layer, u32 dst_level,
|
void D3D12Device::CopyTextureRegion(GPUTexture* dst, u32 dst_x, u32 dst_y, u32 dst_layer, u32 dst_level,
|
||||||
|
@ -1479,7 +1505,7 @@ void D3D12Device::UnmapIndexBuffer(u32 used_index_count)
|
||||||
|
|
||||||
void D3D12Device::PushUniformBuffer(const void* data, u32 data_size)
|
void D3D12Device::PushUniformBuffer(const void* data, u32 data_size)
|
||||||
{
|
{
|
||||||
static constexpr std::array<u8, static_cast<u8>(GPUPipeline::Layout::MaxCount)> push_parameter = {
|
static constexpr std::array<u8, static_cast<u8>(GPUPipeline::Layout::MaxCount)> push_parameters = {
|
||||||
0, // SingleTextureAndUBO
|
0, // SingleTextureAndUBO
|
||||||
2, // SingleTextureAndPushConstants
|
2, // SingleTextureAndPushConstants
|
||||||
1, // SingleTextureBufferAndPushConstants
|
1, // SingleTextureBufferAndPushConstants
|
||||||
|
@ -1495,8 +1521,10 @@ void D3D12Device::PushUniformBuffer(const void* data, u32 data_size)
|
||||||
}
|
}
|
||||||
|
|
||||||
s_stats.buffer_streamed += data_size;
|
s_stats.buffer_streamed += data_size;
|
||||||
GetCommandList()->SetGraphicsRoot32BitConstants(push_parameter[static_cast<u8>(m_current_pipeline_layout)],
|
|
||||||
data_size / 4u, data, 0);
|
const u32 push_param =
|
||||||
|
push_parameters[static_cast<u8>(m_current_pipeline_layout)] + BoolToUInt8(IsUsingROVRootSignature());
|
||||||
|
GetCommandList()->SetGraphicsRoot32BitConstants(push_param, data_size / 4u, data, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* D3D12Device::MapUniformBuffer(u32 size)
|
void* D3D12Device::MapUniformBuffer(u32 size)
|
||||||
|
@ -1526,63 +1554,96 @@ bool D3D12Device::CreateRootSignatures(Error* error)
|
||||||
{
|
{
|
||||||
D3D12::RootSignatureBuilder rsb;
|
D3D12::RootSignatureBuilder rsb;
|
||||||
|
|
||||||
|
for (u32 rov = 0; rov < 2; rov++)
|
||||||
{
|
{
|
||||||
auto& rs = m_root_signatures[static_cast<u8>(GPUPipeline::Layout::SingleTextureAndUBO)];
|
if (rov && !m_features.raster_order_views)
|
||||||
|
break;
|
||||||
|
|
||||||
rsb.SetInputAssemblerFlag();
|
{
|
||||||
rsb.AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 0, 1, D3D12_SHADER_VISIBILITY_PIXEL);
|
auto& rs = m_root_signatures[rov][static_cast<u8>(GPUPipeline::Layout::SingleTextureAndUBO)];
|
||||||
rsb.AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 0, 1, D3D12_SHADER_VISIBILITY_PIXEL);
|
|
||||||
rsb.AddCBVParameter(0, D3D12_SHADER_VISIBILITY_ALL);
|
|
||||||
if (!(rs = rsb.Create(error, true)))
|
|
||||||
return false;
|
|
||||||
D3D12::SetObjectName(rs.Get(), "Single Texture + UBO Pipeline Layout");
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
rsb.SetInputAssemblerFlag();
|
||||||
auto& rs = m_root_signatures[static_cast<u8>(GPUPipeline::Layout::SingleTextureAndPushConstants)];
|
rsb.AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 0, 1, D3D12_SHADER_VISIBILITY_PIXEL);
|
||||||
|
rsb.AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 0, 1, D3D12_SHADER_VISIBILITY_PIXEL);
|
||||||
|
rsb.AddCBVParameter(0, D3D12_SHADER_VISIBILITY_ALL);
|
||||||
|
if (rov)
|
||||||
|
{
|
||||||
|
rsb.AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 0, MAX_IMAGE_RENDER_TARGETS,
|
||||||
|
D3D12_SHADER_VISIBILITY_PIXEL);
|
||||||
|
}
|
||||||
|
if (!(rs = rsb.Create(error, true)))
|
||||||
|
return false;
|
||||||
|
D3D12::SetObjectName(rs.Get(), "Single Texture + UBO Pipeline Layout");
|
||||||
|
}
|
||||||
|
|
||||||
rsb.SetInputAssemblerFlag();
|
{
|
||||||
rsb.AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 0, 1, D3D12_SHADER_VISIBILITY_PIXEL);
|
auto& rs = m_root_signatures[rov][static_cast<u8>(GPUPipeline::Layout::SingleTextureAndPushConstants)];
|
||||||
rsb.AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 0, 1, D3D12_SHADER_VISIBILITY_PIXEL);
|
|
||||||
rsb.Add32BitConstants(0, UNIFORM_PUSH_CONSTANTS_SIZE / sizeof(u32), D3D12_SHADER_VISIBILITY_ALL);
|
|
||||||
if (!(rs = rsb.Create(error, true)))
|
|
||||||
return false;
|
|
||||||
D3D12::SetObjectName(rs.Get(), "Single Texture Pipeline Layout");
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
rsb.SetInputAssemblerFlag();
|
||||||
auto& rs = m_root_signatures[static_cast<u8>(GPUPipeline::Layout::SingleTextureBufferAndPushConstants)];
|
rsb.AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 0, 1, D3D12_SHADER_VISIBILITY_PIXEL);
|
||||||
|
rsb.AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 0, 1, D3D12_SHADER_VISIBILITY_PIXEL);
|
||||||
|
if (rov)
|
||||||
|
{
|
||||||
|
rsb.AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 0, MAX_IMAGE_RENDER_TARGETS,
|
||||||
|
D3D12_SHADER_VISIBILITY_PIXEL);
|
||||||
|
}
|
||||||
|
rsb.Add32BitConstants(0, UNIFORM_PUSH_CONSTANTS_SIZE / sizeof(u32), D3D12_SHADER_VISIBILITY_ALL);
|
||||||
|
if (!(rs = rsb.Create(error, true)))
|
||||||
|
return false;
|
||||||
|
D3D12::SetObjectName(rs.Get(), "Single Texture Pipeline Layout");
|
||||||
|
}
|
||||||
|
|
||||||
rsb.SetInputAssemblerFlag();
|
{
|
||||||
rsb.AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 0, 1, D3D12_SHADER_VISIBILITY_PIXEL);
|
auto& rs = m_root_signatures[rov][static_cast<u8>(GPUPipeline::Layout::SingleTextureBufferAndPushConstants)];
|
||||||
rsb.Add32BitConstants(0, UNIFORM_PUSH_CONSTANTS_SIZE / sizeof(u32), D3D12_SHADER_VISIBILITY_ALL);
|
|
||||||
if (!(rs = rsb.Create(error, true)))
|
|
||||||
return false;
|
|
||||||
D3D12::SetObjectName(rs.Get(), "Single Texture Buffer + UBO Pipeline Layout");
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
rsb.SetInputAssemblerFlag();
|
||||||
auto& rs = m_root_signatures[static_cast<u8>(GPUPipeline::Layout::MultiTextureAndUBO)];
|
rsb.AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 0, 1, D3D12_SHADER_VISIBILITY_PIXEL);
|
||||||
|
if (rov)
|
||||||
|
{
|
||||||
|
rsb.AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 0, MAX_IMAGE_RENDER_TARGETS,
|
||||||
|
D3D12_SHADER_VISIBILITY_PIXEL);
|
||||||
|
}
|
||||||
|
rsb.Add32BitConstants(0, UNIFORM_PUSH_CONSTANTS_SIZE / sizeof(u32), D3D12_SHADER_VISIBILITY_ALL);
|
||||||
|
if (!(rs = rsb.Create(error, true)))
|
||||||
|
return false;
|
||||||
|
D3D12::SetObjectName(rs.Get(), "Single Texture Buffer + UBO Pipeline Layout");
|
||||||
|
}
|
||||||
|
|
||||||
rsb.SetInputAssemblerFlag();
|
{
|
||||||
rsb.AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 0, MAX_TEXTURE_SAMPLERS, D3D12_SHADER_VISIBILITY_PIXEL);
|
auto& rs = m_root_signatures[rov][static_cast<u8>(GPUPipeline::Layout::MultiTextureAndUBO)];
|
||||||
rsb.AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 0, MAX_TEXTURE_SAMPLERS, D3D12_SHADER_VISIBILITY_PIXEL);
|
|
||||||
rsb.AddCBVParameter(0, D3D12_SHADER_VISIBILITY_ALL);
|
|
||||||
if (!(rs = rsb.Create(error, true)))
|
|
||||||
return false;
|
|
||||||
D3D12::SetObjectName(rs.Get(), "Multi Texture + UBO Pipeline Layout");
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
rsb.SetInputAssemblerFlag();
|
||||||
auto& rs = m_root_signatures[static_cast<u8>(GPUPipeline::Layout::MultiTextureAndPushConstants)];
|
rsb.AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 0, MAX_TEXTURE_SAMPLERS, D3D12_SHADER_VISIBILITY_PIXEL);
|
||||||
|
rsb.AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 0, MAX_TEXTURE_SAMPLERS,
|
||||||
|
D3D12_SHADER_VISIBILITY_PIXEL);
|
||||||
|
rsb.AddCBVParameter(0, D3D12_SHADER_VISIBILITY_ALL);
|
||||||
|
if (rov)
|
||||||
|
{
|
||||||
|
rsb.AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 0, MAX_IMAGE_RENDER_TARGETS,
|
||||||
|
D3D12_SHADER_VISIBILITY_PIXEL);
|
||||||
|
}
|
||||||
|
if (!(rs = rsb.Create(error, true)))
|
||||||
|
return false;
|
||||||
|
D3D12::SetObjectName(rs.Get(), "Multi Texture + UBO Pipeline Layout");
|
||||||
|
}
|
||||||
|
|
||||||
rsb.SetInputAssemblerFlag();
|
{
|
||||||
rsb.AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 0, MAX_TEXTURE_SAMPLERS, D3D12_SHADER_VISIBILITY_PIXEL);
|
auto& rs = m_root_signatures[rov][static_cast<u8>(GPUPipeline::Layout::MultiTextureAndPushConstants)];
|
||||||
rsb.AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 0, MAX_TEXTURE_SAMPLERS, D3D12_SHADER_VISIBILITY_PIXEL);
|
|
||||||
rsb.Add32BitConstants(0, UNIFORM_PUSH_CONSTANTS_SIZE / sizeof(u32), D3D12_SHADER_VISIBILITY_ALL);
|
rsb.SetInputAssemblerFlag();
|
||||||
if (!(rs = rsb.Create(error, true)))
|
rsb.AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 0, MAX_TEXTURE_SAMPLERS, D3D12_SHADER_VISIBILITY_PIXEL);
|
||||||
return false;
|
rsb.AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 0, MAX_TEXTURE_SAMPLERS,
|
||||||
D3D12::SetObjectName(rs.Get(), "Multi Texture Pipeline Layout");
|
D3D12_SHADER_VISIBILITY_PIXEL);
|
||||||
|
if (rov)
|
||||||
|
{
|
||||||
|
rsb.AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 0, MAX_IMAGE_RENDER_TARGETS,
|
||||||
|
D3D12_SHADER_VISIBILITY_PIXEL);
|
||||||
|
}
|
||||||
|
rsb.Add32BitConstants(0, UNIFORM_PUSH_CONSTANTS_SIZE / sizeof(u32), D3D12_SHADER_VISIBILITY_ALL);
|
||||||
|
if (!(rs = rsb.Create(error, true)))
|
||||||
|
return false;
|
||||||
|
D3D12::SetObjectName(rs.Get(), "Multi Texture Pipeline Layout");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -1590,29 +1651,30 @@ bool D3D12Device::CreateRootSignatures(Error* error)
|
||||||
|
|
||||||
void D3D12Device::DestroyRootSignatures()
|
void D3D12Device::DestroyRootSignatures()
|
||||||
{
|
{
|
||||||
for (auto it = m_root_signatures.rbegin(); it != m_root_signatures.rend(); ++it)
|
m_root_signatures.enumerate([](auto& it) { it.Reset(); });
|
||||||
it->Reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void D3D12Device::SetRenderTargets(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds,
|
void D3D12Device::SetRenderTargets(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds,
|
||||||
GPUPipeline::RenderPassFlag feedback_loop)
|
GPUPipeline::RenderPassFlag flags)
|
||||||
{
|
{
|
||||||
DebugAssert(!feedback_loop);
|
DebugAssert(
|
||||||
|
!(flags & (GPUPipeline::RenderPassFlag::ColorFeedbackLoop | GPUPipeline::RenderPassFlag::SampleDepthBuffer)));
|
||||||
if (InRenderPass())
|
if (InRenderPass())
|
||||||
EndRenderPass();
|
EndRenderPass();
|
||||||
|
|
||||||
ID3D12GraphicsCommandList4* cmdlist = GetCommandList();
|
|
||||||
|
|
||||||
m_current_depth_target = static_cast<D3D12Texture*>(ds);
|
m_current_depth_target = static_cast<D3D12Texture*>(ds);
|
||||||
for (u32 i = 0; i < num_rts; i++)
|
if (num_rts > 0)
|
||||||
{
|
std::memcpy(m_current_render_targets.data(), rts, sizeof(D3D12Texture*) * num_rts);
|
||||||
D3D12Texture* const dt = static_cast<D3D12Texture*>(rts[i]);
|
|
||||||
m_current_render_targets[i] = dt;
|
|
||||||
dt->CommitClear(cmdlist);
|
|
||||||
}
|
|
||||||
for (u32 i = num_rts; i < m_num_current_render_targets; i++)
|
for (u32 i = num_rts; i < m_num_current_render_targets; i++)
|
||||||
m_current_render_targets[i] = nullptr;
|
m_current_render_targets[i] = nullptr;
|
||||||
m_num_current_render_targets = num_rts;
|
m_num_current_render_targets = num_rts;
|
||||||
|
|
||||||
|
// Need a root signature change if switching to UAVs.
|
||||||
|
m_dirty_flags |=
|
||||||
|
((m_current_render_pass_flags ^ flags) & GPUPipeline::BindRenderTargetsAsImages) ? LAYOUT_DEPENDENT_DIRTY_STATE : 0;
|
||||||
|
m_dirty_flags = (flags & GPUPipeline::BindRenderTargetsAsImages) ? (m_dirty_flags | DIRTY_FLAG_RT_UAVS) :
|
||||||
|
(m_dirty_flags & ~DIRTY_FLAG_RT_UAVS);
|
||||||
|
m_current_render_pass_flags = flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
void D3D12Device::BeginRenderPass()
|
void D3D12Device::BeginRenderPass()
|
||||||
|
@ -1630,48 +1692,62 @@ void D3D12Device::BeginRenderPass()
|
||||||
|
|
||||||
if (m_num_current_render_targets > 0 || m_current_depth_target) [[likely]]
|
if (m_num_current_render_targets > 0 || m_current_depth_target) [[likely]]
|
||||||
{
|
{
|
||||||
for (u32 i = 0; i < m_num_current_render_targets; i++)
|
if (!IsUsingROVRootSignature()) [[likely]]
|
||||||
{
|
{
|
||||||
D3D12Texture* const rt = m_current_render_targets[i];
|
for (u32 i = 0; i < m_num_current_render_targets; i++)
|
||||||
rt->TransitionToState(cmdlist, D3D12_RESOURCE_STATE_RENDER_TARGET);
|
|
||||||
rt->SetUseFenceValue(GetCurrentFenceValue());
|
|
||||||
|
|
||||||
D3D12_RENDER_PASS_RENDER_TARGET_DESC& desc = rt_desc[i];
|
|
||||||
desc.cpuDescriptor = rt->GetWriteDescriptor();
|
|
||||||
desc.EndingAccess.Type = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE;
|
|
||||||
|
|
||||||
switch (rt->GetState())
|
|
||||||
{
|
{
|
||||||
case GPUTexture::State::Cleared:
|
D3D12Texture* const rt = m_current_render_targets[i];
|
||||||
{
|
rt->TransitionToState(cmdlist, D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||||
desc.BeginningAccess.Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR;
|
rt->SetUseFenceValue(GetCurrentFenceValue());
|
||||||
std::memcpy(desc.BeginningAccess.Clear.ClearValue.Color, rt->GetUNormClearColor().data(),
|
|
||||||
sizeof(desc.BeginningAccess.Clear.ClearValue.Color));
|
|
||||||
rt->SetState(GPUTexture::State::Dirty);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GPUTexture::State::Invalidated:
|
D3D12_RENDER_PASS_RENDER_TARGET_DESC& desc = rt_desc[i];
|
||||||
{
|
desc.cpuDescriptor = rt->GetWriteDescriptor();
|
||||||
desc.BeginningAccess.Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_DISCARD;
|
desc.EndingAccess.Type = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE;
|
||||||
rt->SetState(GPUTexture::State::Dirty);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GPUTexture::State::Dirty:
|
switch (rt->GetState())
|
||||||
{
|
{
|
||||||
desc.BeginningAccess.Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE;
|
case GPUTexture::State::Cleared:
|
||||||
}
|
{
|
||||||
break;
|
desc.BeginningAccess.Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR;
|
||||||
|
std::memcpy(desc.BeginningAccess.Clear.ClearValue.Color, rt->GetUNormClearColor().data(),
|
||||||
default:
|
sizeof(desc.BeginningAccess.Clear.ClearValue.Color));
|
||||||
UnreachableCode();
|
rt->SetState(GPUTexture::State::Dirty);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case GPUTexture::State::Invalidated:
|
||||||
|
{
|
||||||
|
desc.BeginningAccess.Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_DISCARD;
|
||||||
|
rt->SetState(GPUTexture::State::Dirty);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GPUTexture::State::Dirty:
|
||||||
|
{
|
||||||
|
desc.BeginningAccess.Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
UnreachableCode();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rt_desc_p = (m_num_current_render_targets > 0) ? rt_desc.data() : nullptr;
|
||||||
|
num_rt_descs = m_num_current_render_targets;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Still need to clear the RTs.
|
||||||
|
for (u32 i = 0; i < m_num_current_render_targets; i++)
|
||||||
|
{
|
||||||
|
D3D12Texture* const rt = m_current_render_targets[i];
|
||||||
|
rt->TransitionToState(cmdlist, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
|
||||||
|
rt->SetUseFenceValue(GetCurrentFenceValue());
|
||||||
|
rt->CommitClear(cmdlist);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rt_desc_p = (m_num_current_render_targets > 0) ? rt_desc.data() : nullptr;
|
|
||||||
num_rt_descs = m_num_current_render_targets;
|
|
||||||
if (m_current_depth_target)
|
if (m_current_depth_target)
|
||||||
{
|
{
|
||||||
D3D12Texture* const ds = m_current_depth_target;
|
D3D12Texture* const ds = m_current_depth_target;
|
||||||
|
@ -1733,7 +1809,7 @@ void D3D12Device::BeginRenderPass()
|
||||||
m_current_textures[i]->TransitionToState(cmdlist, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
m_current_textures[i]->TransitionToState(cmdlist, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
DebugAssert(rt_desc_p || ds_desc_p);
|
DebugAssert(rt_desc_p || ds_desc_p || IsUsingROVRootSignature());
|
||||||
cmdlist->BeginRenderPass(num_rt_descs, rt_desc_p, ds_desc_p, D3D12_RENDER_PASS_FLAG_NONE);
|
cmdlist->BeginRenderPass(num_rt_descs, rt_desc_p, ds_desc_p, D3D12_RENDER_PASS_FLAG_NONE);
|
||||||
|
|
||||||
// TODO: Stats
|
// TODO: Stats
|
||||||
|
@ -1771,6 +1847,9 @@ void D3D12Device::BeginSwapChainRenderPass()
|
||||||
|
|
||||||
std::memset(m_current_render_targets.data(), 0, sizeof(m_current_render_targets));
|
std::memset(m_current_render_targets.data(), 0, sizeof(m_current_render_targets));
|
||||||
m_num_current_render_targets = 0;
|
m_num_current_render_targets = 0;
|
||||||
|
m_dirty_flags =
|
||||||
|
(m_dirty_flags & ~DIRTY_FLAG_RT_UAVS) | ((IsUsingROVRootSignature()) ? DIRTY_FLAG_PIPELINE_LAYOUT : 0);
|
||||||
|
m_current_render_pass_flags = GPUPipeline::NoRenderPassFlags;
|
||||||
m_current_depth_target = nullptr;
|
m_current_depth_target = nullptr;
|
||||||
m_in_render_pass = true;
|
m_in_render_pass = true;
|
||||||
s_stats.num_render_passes++;
|
s_stats.num_render_passes++;
|
||||||
|
@ -1839,8 +1918,7 @@ void D3D12Device::SetPipeline(GPUPipeline* pipeline)
|
||||||
if (GPUPipeline::Layout layout = m_current_pipeline->GetLayout(); m_current_pipeline_layout != layout)
|
if (GPUPipeline::Layout layout = m_current_pipeline->GetLayout(); m_current_pipeline_layout != layout)
|
||||||
{
|
{
|
||||||
m_current_pipeline_layout = layout;
|
m_current_pipeline_layout = layout;
|
||||||
m_dirty_flags |=
|
m_dirty_flags |= LAYOUT_DEPENDENT_DIRTY_STATE & (IsUsingROVRootSignature() ? ~0u : ~DIRTY_FLAG_RT_UAVS);
|
||||||
DIRTY_FLAG_PIPELINE_LAYOUT | DIRTY_FLAG_CONSTANT_BUFFER | DIRTY_FLAG_TEXTURES | DIRTY_FLAG_SAMPLERS;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1865,7 +1943,8 @@ bool D3D12Device::IsRenderTargetBound(const GPUTexture* tex) const
|
||||||
|
|
||||||
void D3D12Device::InvalidateCachedState()
|
void D3D12Device::InvalidateCachedState()
|
||||||
{
|
{
|
||||||
m_dirty_flags = ALL_DIRTY_STATE;
|
m_dirty_flags = ALL_DIRTY_STATE &
|
||||||
|
((m_current_render_pass_flags & GPUPipeline::BindRenderTargetsAsImages) ? ~0u : ~DIRTY_FLAG_RT_UAVS);
|
||||||
m_in_render_pass = false;
|
m_in_render_pass = false;
|
||||||
m_current_pipeline = nullptr;
|
m_current_pipeline = nullptr;
|
||||||
m_current_vertex_stride = 0;
|
m_current_vertex_stride = 0;
|
||||||
|
@ -2053,7 +2132,7 @@ void D3D12Device::PreDrawCheck()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (dirty & (DIRTY_FLAG_CONSTANT_BUFFER | DIRTY_FLAG_TEXTURES | DIRTY_FLAG_SAMPLERS))
|
else if (dirty & (DIRTY_FLAG_CONSTANT_BUFFER | DIRTY_FLAG_TEXTURES | DIRTY_FLAG_SAMPLERS | DIRTY_FLAG_RT_UAVS))
|
||||||
{
|
{
|
||||||
if (!UpdateRootParameters(dirty))
|
if (!UpdateRootParameters(dirty))
|
||||||
{
|
{
|
||||||
|
@ -2068,9 +2147,15 @@ void D3D12Device::PreDrawCheck()
|
||||||
BeginRenderPass();
|
BeginRenderPass();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool D3D12Device::IsUsingROVRootSignature() const
|
||||||
|
{
|
||||||
|
return ((m_current_render_pass_flags & GPUPipeline::BindRenderTargetsAsImages) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
void D3D12Device::UpdateRootSignature()
|
void D3D12Device::UpdateRootSignature()
|
||||||
{
|
{
|
||||||
GetCommandList()->SetGraphicsRootSignature(m_root_signatures[static_cast<u8>(m_current_pipeline_layout)].Get());
|
GetCommandList()->SetGraphicsRootSignature(
|
||||||
|
m_root_signatures[BoolToUInt8(IsUsingROVRootSignature())][static_cast<u8>(m_current_pipeline_layout)].Get());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<GPUPipeline::Layout layout>
|
template<GPUPipeline::Layout layout>
|
||||||
|
@ -2145,6 +2230,35 @@ bool D3D12Device::UpdateParametersForLayout(u32 dirty)
|
||||||
cmdlist->SetGraphicsRootDescriptorTable(0, gpu_handle);
|
cmdlist->SetGraphicsRootDescriptorTable(0, gpu_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dirty & DIRTY_FLAG_RT_UAVS)
|
||||||
|
{
|
||||||
|
DebugAssert(m_current_render_pass_flags & GPUPipeline::BindRenderTargetsAsImages);
|
||||||
|
|
||||||
|
D3D12DescriptorAllocator& allocator = m_command_lists[m_current_command_list].descriptor_allocator;
|
||||||
|
D3D12DescriptorHandle gpu_handle;
|
||||||
|
if (!allocator.Allocate(MAX_IMAGE_RENDER_TARGETS, &gpu_handle))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE src_handles[MAX_IMAGE_RENDER_TARGETS];
|
||||||
|
UINT src_sizes[MAX_IMAGE_RENDER_TARGETS];
|
||||||
|
const UINT dst_size = MAX_IMAGE_RENDER_TARGETS;
|
||||||
|
for (u32 i = 0; i < MAX_IMAGE_RENDER_TARGETS; i++)
|
||||||
|
{
|
||||||
|
src_handles[i] =
|
||||||
|
m_current_render_targets[i] ? m_current_render_targets[i]->GetSRVDescriptor() : m_null_srv_descriptor;
|
||||||
|
src_sizes[i] = 1;
|
||||||
|
}
|
||||||
|
m_device->CopyDescriptors(1, &gpu_handle.cpu_handle, &dst_size, MAX_IMAGE_RENDER_TARGETS, src_handles, src_sizes,
|
||||||
|
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
|
||||||
|
|
||||||
|
constexpr u32 rov_param =
|
||||||
|
(layout == GPUPipeline::Layout::SingleTextureBufferAndPushConstants) ?
|
||||||
|
1 :
|
||||||
|
((layout == GPUPipeline::Layout::SingleTextureAndUBO || layout == GPUPipeline::Layout::MultiTextureAndUBO) ? 3 :
|
||||||
|
2);
|
||||||
|
cmdlist->SetGraphicsRootDescriptorTable(rov_param, gpu_handle);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "gpu_device.h"
|
#include "gpu_device.h"
|
||||||
#include "gpu_texture.h"
|
#include "gpu_texture.h"
|
||||||
|
|
||||||
|
#include "common/dimensional_array.h"
|
||||||
#include "common/windows_headers.h"
|
#include "common/windows_headers.h"
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
@ -110,7 +111,7 @@ public:
|
||||||
void* MapUniformBuffer(u32 size) override;
|
void* MapUniformBuffer(u32 size) override;
|
||||||
void UnmapUniformBuffer(u32 size) override;
|
void UnmapUniformBuffer(u32 size) override;
|
||||||
void SetRenderTargets(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds,
|
void SetRenderTargets(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds,
|
||||||
GPUPipeline::RenderPassFlag feedback_loop = GPUPipeline::NoRenderPassFlags) override;
|
GPUPipeline::RenderPassFlag flags = GPUPipeline::NoRenderPassFlags) override;
|
||||||
void SetPipeline(GPUPipeline* pipeline) override;
|
void SetPipeline(GPUPipeline* pipeline) override;
|
||||||
void SetTextureSampler(u32 slot, GPUTexture* texture, GPUSampler* sampler) override;
|
void SetTextureSampler(u32 slot, GPUTexture* texture, GPUSampler* sampler) override;
|
||||||
void SetTextureBuffer(u32 slot, GPUTextureBuffer* buffer) override;
|
void SetTextureBuffer(u32 slot, GPUTextureBuffer* buffer) override;
|
||||||
|
@ -200,9 +201,11 @@ private:
|
||||||
DIRTY_FLAG_CONSTANT_BUFFER = (1 << 2),
|
DIRTY_FLAG_CONSTANT_BUFFER = (1 << 2),
|
||||||
DIRTY_FLAG_TEXTURES = (1 << 3),
|
DIRTY_FLAG_TEXTURES = (1 << 3),
|
||||||
DIRTY_FLAG_SAMPLERS = (1 << 3),
|
DIRTY_FLAG_SAMPLERS = (1 << 3),
|
||||||
|
DIRTY_FLAG_RT_UAVS = (1 << 4),
|
||||||
|
|
||||||
ALL_DIRTY_STATE = DIRTY_FLAG_INITIAL | DIRTY_FLAG_PIPELINE_LAYOUT | DIRTY_FLAG_CONSTANT_BUFFER |
|
LAYOUT_DEPENDENT_DIRTY_STATE = DIRTY_FLAG_PIPELINE_LAYOUT | DIRTY_FLAG_CONSTANT_BUFFER | DIRTY_FLAG_TEXTURES |
|
||||||
DIRTY_FLAG_TEXTURES | DIRTY_FLAG_SAMPLERS,
|
DIRTY_FLAG_SAMPLERS | DIRTY_FLAG_RT_UAVS,
|
||||||
|
ALL_DIRTY_STATE = DIRTY_FLAG_INITIAL | (LAYOUT_DEPENDENT_DIRTY_STATE & ~DIRTY_FLAG_RT_UAVS),
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CommandList
|
struct CommandList
|
||||||
|
@ -264,6 +267,7 @@ private:
|
||||||
void SetInitialPipelineState();
|
void SetInitialPipelineState();
|
||||||
void PreDrawCheck();
|
void PreDrawCheck();
|
||||||
|
|
||||||
|
bool IsUsingROVRootSignature() const;
|
||||||
void UpdateRootSignature();
|
void UpdateRootSignature();
|
||||||
template<GPUPipeline::Layout layout>
|
template<GPUPipeline::Layout layout>
|
||||||
bool UpdateParametersForLayout(u32 dirty);
|
bool UpdateParametersForLayout(u32 dirty);
|
||||||
|
@ -303,6 +307,7 @@ private:
|
||||||
D3D12DescriptorHeapManager m_dsv_heap_manager;
|
D3D12DescriptorHeapManager m_dsv_heap_manager;
|
||||||
D3D12DescriptorHeapManager m_sampler_heap_manager;
|
D3D12DescriptorHeapManager m_sampler_heap_manager;
|
||||||
D3D12DescriptorHandle m_null_srv_descriptor;
|
D3D12DescriptorHandle m_null_srv_descriptor;
|
||||||
|
D3D12DescriptorHandle m_null_uav_descriptor;
|
||||||
D3D12DescriptorHandle m_point_sampler;
|
D3D12DescriptorHandle m_point_sampler;
|
||||||
|
|
||||||
ComPtr<ID3D12QueryHeap> m_timestamp_query_heap;
|
ComPtr<ID3D12QueryHeap> m_timestamp_query_heap;
|
||||||
|
@ -314,7 +319,8 @@ private:
|
||||||
std::deque<std::pair<u64, std::pair<D3D12MA::Allocation*, ID3D12Object*>>> m_cleanup_resources;
|
std::deque<std::pair<u64, std::pair<D3D12MA::Allocation*, ID3D12Object*>>> m_cleanup_resources;
|
||||||
std::deque<std::pair<u64, std::pair<D3D12DescriptorHeapManager*, D3D12DescriptorHandle>>> m_cleanup_descriptors;
|
std::deque<std::pair<u64, std::pair<D3D12DescriptorHeapManager*, D3D12DescriptorHandle>>> m_cleanup_descriptors;
|
||||||
|
|
||||||
std::array<ComPtr<ID3D12RootSignature>, static_cast<u8>(GPUPipeline::Layout::MaxCount)> m_root_signatures = {};
|
DimensionalArray<ComPtr<ID3D12RootSignature>, static_cast<u8>(GPUPipeline::Layout::MaxCount), 2> m_root_signatures =
|
||||||
|
{};
|
||||||
|
|
||||||
D3D12StreamBuffer m_vertex_buffer;
|
D3D12StreamBuffer m_vertex_buffer;
|
||||||
D3D12StreamBuffer m_index_buffer;
|
D3D12StreamBuffer m_index_buffer;
|
||||||
|
@ -333,6 +339,7 @@ private:
|
||||||
D3D12Pipeline* m_current_pipeline = nullptr;
|
D3D12Pipeline* m_current_pipeline = nullptr;
|
||||||
D3D12_PRIMITIVE_TOPOLOGY m_current_topology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED;
|
D3D12_PRIMITIVE_TOPOLOGY m_current_topology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED;
|
||||||
u32 m_num_current_render_targets = 0;
|
u32 m_num_current_render_targets = 0;
|
||||||
|
GPUPipeline::RenderPassFlag m_current_render_pass_flags = GPUPipeline::NoRenderPassFlags;
|
||||||
std::array<D3D12Texture*, MAX_RENDER_TARGETS> m_current_render_targets = {};
|
std::array<D3D12Texture*, MAX_RENDER_TARGETS> m_current_render_targets = {};
|
||||||
D3D12Texture* m_current_depth_target = nullptr;
|
D3D12Texture* m_current_depth_target = nullptr;
|
||||||
u32 m_current_vertex_stride = 0;
|
u32 m_current_vertex_stride = 0;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
|
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
||||||
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||||
|
|
||||||
#include "d3d12_pipeline.h"
|
#include "d3d12_pipeline.h"
|
||||||
|
@ -7,6 +7,7 @@
|
||||||
#include "d3d_common.h"
|
#include "d3d_common.h"
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
|
#include "common/bitutils.h"
|
||||||
#include "common/log.h"
|
#include "common/log.h"
|
||||||
#include "common/sha1_digest.h"
|
#include "common/sha1_digest.h"
|
||||||
#include "common/string_util.h"
|
#include "common/string_util.h"
|
||||||
|
@ -180,8 +181,16 @@ std::unique_ptr<GPUPipeline> D3D12Device::CreatePipeline(const GPUPipeline::Grap
|
||||||
D3D12_BLEND_OP_MAX, // Max
|
D3D12_BLEND_OP_MAX, // Max
|
||||||
}};
|
}};
|
||||||
|
|
||||||
|
if (config.render_pass_flags & GPUPipeline::BindRenderTargetsAsImages && !m_features.raster_order_views)
|
||||||
|
{
|
||||||
|
ERROR_LOG("Attempting to create ROV pipeline without ROV feature.");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
D3D12::GraphicsPipelineBuilder gpb;
|
D3D12::GraphicsPipelineBuilder gpb;
|
||||||
gpb.SetRootSignature(m_root_signatures[static_cast<u8>(config.layout)].Get());
|
gpb.SetRootSignature(m_root_signatures[BoolToUInt8(
|
||||||
|
(config.render_pass_flags & GPUPipeline::BindRenderTargetsAsImages))][static_cast<u8>(config.layout)]
|
||||||
|
.Get());
|
||||||
gpb.SetVertexShader(static_cast<const D3D12Shader*>(config.vertex_shader)->GetBytecodeData(),
|
gpb.SetVertexShader(static_cast<const D3D12Shader*>(config.vertex_shader)->GetBytecodeData(),
|
||||||
static_cast<const D3D12Shader*>(config.vertex_shader)->GetBytecodeSize());
|
static_cast<const D3D12Shader*>(config.vertex_shader)->GetBytecodeSize());
|
||||||
gpb.SetPixelShader(static_cast<const D3D12Shader*>(config.fragment_shader)->GetBytecodeData(),
|
gpb.SetPixelShader(static_cast<const D3D12Shader*>(config.fragment_shader)->GetBytecodeData(),
|
||||||
|
|
|
@ -44,8 +44,6 @@ std::unique_ptr<GPUTexture> D3D12Device::CreateTexture(u32 width, u32 height, u3
|
||||||
|
|
||||||
const D3DCommon::DXGIFormatMapping& fm = D3DCommon::GetFormatMapping(format);
|
const D3DCommon::DXGIFormatMapping& fm = D3DCommon::GetFormatMapping(format);
|
||||||
|
|
||||||
const DXGI_FORMAT uav_format = (type == GPUTexture::Type::RWTexture) ? fm.resource_format : DXGI_FORMAT_UNKNOWN;
|
|
||||||
|
|
||||||
D3D12_RESOURCE_DESC desc = {};
|
D3D12_RESOURCE_DESC desc = {};
|
||||||
desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
||||||
desc.Width = width;
|
desc.Width = width;
|
||||||
|
@ -98,7 +96,9 @@ std::unique_ptr<GPUTexture> D3D12Device::CreateTexture(u32 width, u32 height, u3
|
||||||
{
|
{
|
||||||
DebugAssert(levels == 1);
|
DebugAssert(levels == 1);
|
||||||
allocationDesc.Flags |= D3D12MA::ALLOCATION_FLAG_COMMITTED;
|
allocationDesc.Flags |= D3D12MA::ALLOCATION_FLAG_COMMITTED;
|
||||||
state = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
|
||||||
|
optimized_clear_value.Format = fm.rtv_format;
|
||||||
|
state = D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -106,9 +106,6 @@ std::unique_ptr<GPUTexture> D3D12Device::CreateTexture(u32 width, u32 height, u3
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uav_format != DXGI_FORMAT_UNKNOWN)
|
|
||||||
desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
|
|
||||||
|
|
||||||
ComPtr<ID3D12Resource> resource;
|
ComPtr<ID3D12Resource> resource;
|
||||||
ComPtr<D3D12MA::Allocation> allocation;
|
ComPtr<D3D12MA::Allocation> allocation;
|
||||||
HRESULT hr = m_allocator->CreateResource(
|
HRESULT hr = m_allocator->CreateResource(
|
||||||
|
@ -157,18 +154,28 @@ std::unique_ptr<GPUTexture> D3D12Device::CreateTexture(u32 width, u32 height, u3
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case GPUTexture::Type::RWTexture:
|
||||||
|
{
|
||||||
|
write_descriptor_type = D3D12Texture::WriteDescriptorType::RTV;
|
||||||
|
if (!CreateRTVDescriptor(resource.Get(), samples, fm.rtv_format, &write_descriptor))
|
||||||
|
{
|
||||||
|
m_descriptor_heap_manager.Free(&srv_descriptor);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CreateUAVDescriptor(resource.Get(), samples, fm.srv_format, &uav_descriptor))
|
||||||
|
{
|
||||||
|
m_descriptor_heap_manager.Free(&write_descriptor);
|
||||||
|
m_descriptor_heap_manager.Free(&srv_descriptor);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uav_format != DXGI_FORMAT_UNKNOWN &&
|
|
||||||
!CreateUAVDescriptor(resource.Get(), samples, fm.dsv_format, &uav_descriptor))
|
|
||||||
{
|
|
||||||
m_descriptor_heap_manager.Free(&write_descriptor);
|
|
||||||
m_descriptor_heap_manager.Free(&srv_descriptor);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<D3D12Texture> tex(new D3D12Texture(
|
std::unique_ptr<D3D12Texture> tex(new D3D12Texture(
|
||||||
width, height, layers, levels, samples, type, format, fm.resource_format, std::move(resource),
|
width, height, layers, levels, samples, type, format, fm.resource_format, std::move(resource),
|
||||||
std::move(allocation), srv_descriptor, write_descriptor, uav_descriptor, write_descriptor_type, state));
|
std::move(allocation), srv_descriptor, write_descriptor, uav_descriptor, write_descriptor_type, state));
|
||||||
|
|
|
@ -50,7 +50,7 @@ const char* D3DCommon::GetFeatureLevelShaderModelString(D3D_FEATURE_LEVEL featur
|
||||||
{D3D_FEATURE_LEVEL_10_0, "sm40"},
|
{D3D_FEATURE_LEVEL_10_0, "sm40"},
|
||||||
{D3D_FEATURE_LEVEL_10_1, "sm41"},
|
{D3D_FEATURE_LEVEL_10_1, "sm41"},
|
||||||
{D3D_FEATURE_LEVEL_11_0, "sm50"},
|
{D3D_FEATURE_LEVEL_11_0, "sm50"},
|
||||||
{D3D_FEATURE_LEVEL_11_1, "sm51"},
|
{D3D_FEATURE_LEVEL_11_1, "sm50"},
|
||||||
}};
|
}};
|
||||||
|
|
||||||
for (const auto& [fl, name] : feature_level_names)
|
for (const auto& [fl, name] : feature_level_names)
|
||||||
|
@ -390,11 +390,9 @@ u32 D3DCommon::GetShaderModelForFeatureLevel(D3D_FEATURE_LEVEL feature_level)
|
||||||
return 41;
|
return 41;
|
||||||
|
|
||||||
case D3D_FEATURE_LEVEL_11_0:
|
case D3D_FEATURE_LEVEL_11_0:
|
||||||
return 50;
|
|
||||||
|
|
||||||
case D3D_FEATURE_LEVEL_11_1:
|
case D3D_FEATURE_LEVEL_11_1:
|
||||||
default:
|
default:
|
||||||
return 51;
|
return 50;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -429,14 +427,6 @@ std::optional<DynamicHeapArray<u8>> D3DCommon::CompileShader(u32 shader_model, b
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 51:
|
|
||||||
{
|
|
||||||
static constexpr std::array<const char*, static_cast<u32>(GPUShaderStage::MaxCount)> targets = {
|
|
||||||
{"vs_5_1", "ps_5_1", "gs_5_1", "cs_5_1"}};
|
|
||||||
target = targets[static_cast<int>(stage)];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
Error::SetStringFmt(error, "Unknown shader model: {}", shader_model);
|
Error::SetStringFmt(error, "Unknown shader model: {}", shader_model);
|
||||||
return {};
|
return {};
|
||||||
|
|
|
@ -168,6 +168,7 @@ public:
|
||||||
NoRenderPassFlags = 0,
|
NoRenderPassFlags = 0,
|
||||||
ColorFeedbackLoop = (1 << 0),
|
ColorFeedbackLoop = (1 << 0),
|
||||||
SampleDepthBuffer = (1 << 1),
|
SampleDepthBuffer = (1 << 1),
|
||||||
|
BindRenderTargetsAsImages = (1 << 2),
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class Primitive : u8
|
enum class Primitive : u8
|
||||||
|
@ -469,6 +470,7 @@ public:
|
||||||
FEATURE_MASK_GEOMETRY_SHADERS = (1 << 4),
|
FEATURE_MASK_GEOMETRY_SHADERS = (1 << 4),
|
||||||
FEATURE_MASK_TEXTURE_COPY_TO_SELF = (1 << 5),
|
FEATURE_MASK_TEXTURE_COPY_TO_SELF = (1 << 5),
|
||||||
FEATURE_MASK_MEMORY_IMPORT = (1 << 6),
|
FEATURE_MASK_MEMORY_IMPORT = (1 << 6),
|
||||||
|
FEATURE_MASK_RASTER_ORDER_VIEWS = (1 << 7),
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class DrawBarrier : u32
|
enum class DrawBarrier : u32
|
||||||
|
@ -496,6 +498,7 @@ public:
|
||||||
bool shader_cache : 1;
|
bool shader_cache : 1;
|
||||||
bool pipeline_cache : 1;
|
bool pipeline_cache : 1;
|
||||||
bool prefer_unused_textures : 1;
|
bool prefer_unused_textures : 1;
|
||||||
|
bool raster_order_views : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Statistics
|
struct Statistics
|
||||||
|
@ -527,6 +530,7 @@ public:
|
||||||
static constexpr u32 MAX_TEXTURE_SAMPLERS = 8;
|
static constexpr u32 MAX_TEXTURE_SAMPLERS = 8;
|
||||||
static constexpr u32 MIN_TEXEL_BUFFER_ELEMENTS = 4 * 1024 * 512;
|
static constexpr u32 MIN_TEXEL_BUFFER_ELEMENTS = 4 * 1024 * 512;
|
||||||
static constexpr u32 MAX_RENDER_TARGETS = 4;
|
static constexpr u32 MAX_RENDER_TARGETS = 4;
|
||||||
|
static constexpr u32 MAX_IMAGE_RENDER_TARGETS = 2;
|
||||||
static_assert(sizeof(GPUPipeline::GraphicsConfig::color_formats) == sizeof(GPUTexture::Format) * MAX_RENDER_TARGETS);
|
static_assert(sizeof(GPUPipeline::GraphicsConfig::color_formats) == sizeof(GPUTexture::Format) * MAX_RENDER_TARGETS);
|
||||||
|
|
||||||
GPUDevice();
|
GPUDevice();
|
||||||
|
@ -676,14 +680,14 @@ public:
|
||||||
|
|
||||||
/// Drawing setup abstraction.
|
/// Drawing setup abstraction.
|
||||||
virtual void SetRenderTargets(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds,
|
virtual void SetRenderTargets(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds,
|
||||||
GPUPipeline::RenderPassFlag render_pass_flags = GPUPipeline::NoRenderPassFlags) = 0;
|
GPUPipeline::RenderPassFlag flags = GPUPipeline::NoRenderPassFlags) = 0;
|
||||||
virtual void SetPipeline(GPUPipeline* pipeline) = 0;
|
virtual void SetPipeline(GPUPipeline* pipeline) = 0;
|
||||||
virtual void SetTextureSampler(u32 slot, GPUTexture* texture, GPUSampler* sampler) = 0;
|
virtual void SetTextureSampler(u32 slot, GPUTexture* texture, GPUSampler* sampler) = 0;
|
||||||
virtual void SetTextureBuffer(u32 slot, GPUTextureBuffer* buffer) = 0;
|
virtual void SetTextureBuffer(u32 slot, GPUTextureBuffer* buffer) = 0;
|
||||||
virtual void SetViewport(const GSVector4i rc) = 0;
|
virtual void SetViewport(const GSVector4i rc) = 0;
|
||||||
virtual void SetScissor(const GSVector4i rc) = 0;
|
virtual void SetScissor(const GSVector4i rc) = 0;
|
||||||
void SetRenderTarget(GPUTexture* rt, GPUTexture* ds = nullptr,
|
void SetRenderTarget(GPUTexture* rt, GPUTexture* ds = nullptr,
|
||||||
GPUPipeline::RenderPassFlag render_pass_flags = GPUPipeline::NoRenderPassFlags);
|
GPUPipeline::RenderPassFlag flags = GPUPipeline::NoRenderPassFlags);
|
||||||
void SetViewport(s32 x, s32 y, s32 width, s32 height);
|
void SetViewport(s32 x, s32 y, s32 width, s32 height);
|
||||||
void SetScissor(s32 x, s32 y, s32 width, s32 height);
|
void SetScissor(s32 x, s32 y, s32 width, s32 height);
|
||||||
void SetViewportAndScissor(s32 x, s32 y, s32 width, s32 height);
|
void SetViewportAndScissor(s32 x, s32 y, s32 width, s32 height);
|
||||||
|
|
|
@ -213,10 +213,18 @@ bool GPUTexture::ValidateConfig(u32 width, u32 height, u32 layers, u32 levels, u
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (samples > 1 && levels > 1)
|
if (samples > 1)
|
||||||
{
|
{
|
||||||
ERROR_LOG("Multisampled textures can't have mip levels.");
|
if (levels > 1)
|
||||||
return false;
|
{
|
||||||
|
ERROR_LOG("Multisampled textures can't have mip levels.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (type != Type::RenderTarget && type != Type::DepthStencil)
|
||||||
|
{
|
||||||
|
ERROR_LOG("Multisampled textures must be render targets or depth stencil targets.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (layers > 1 && type != Type::Texture && type != Type::DynamicTexture)
|
if (layers > 1 && type != Type::Texture && type != Type::DynamicTexture)
|
||||||
|
|
|
@ -129,6 +129,7 @@ public:
|
||||||
ALWAYS_INLINE bool IsDepthStencil() const { return (m_type == Type::DepthStencil); }
|
ALWAYS_INLINE bool IsDepthStencil() const { return (m_type == Type::DepthStencil); }
|
||||||
ALWAYS_INLINE bool IsTexture() const { return (m_type == Type::Texture || m_type == Type::DynamicTexture); }
|
ALWAYS_INLINE bool IsTexture() const { return (m_type == Type::Texture || m_type == Type::DynamicTexture); }
|
||||||
ALWAYS_INLINE bool IsDynamicTexture() const { return (m_type == Type::DynamicTexture); }
|
ALWAYS_INLINE bool IsDynamicTexture() const { return (m_type == Type::DynamicTexture); }
|
||||||
|
ALWAYS_INLINE bool IsRWTexture() const { return (m_type == Type::RWTexture); }
|
||||||
|
|
||||||
ALWAYS_INLINE const ClearValue& GetClearValue() const { return m_clear_value; }
|
ALWAYS_INLINE const ClearValue& GetClearValue() const { return m_clear_value; }
|
||||||
ALWAYS_INLINE u32 GetClearColor() const { return m_clear_value.color; }
|
ALWAYS_INLINE u32 GetClearColor() const { return m_clear_value.color; }
|
||||||
|
|
|
@ -481,7 +481,7 @@ bool OpenGLDevice::CheckFeatures(FeatureMask disabled_features)
|
||||||
// So, blit from the shadow texture, like in the other renderers.
|
// So, blit from the shadow texture, like in the other renderers.
|
||||||
m_features.texture_copy_to_self = !vendor_id_arm && !(disabled_features & FEATURE_MASK_TEXTURE_COPY_TO_SELF);
|
m_features.texture_copy_to_self = !vendor_id_arm && !(disabled_features & FEATURE_MASK_TEXTURE_COPY_TO_SELF);
|
||||||
|
|
||||||
m_features.feedback_loops = m_features.framebuffer_fetch;
|
m_features.feedback_loops = false;
|
||||||
|
|
||||||
m_features.geometry_shaders =
|
m_features.geometry_shaders =
|
||||||
!(disabled_features & FEATURE_MASK_GEOMETRY_SHADERS) && (GLAD_GL_VERSION_3_2 || GLAD_GL_ES_VERSION_3_2);
|
!(disabled_features & FEATURE_MASK_GEOMETRY_SHADERS) && (GLAD_GL_VERSION_3_2 || GLAD_GL_ES_VERSION_3_2);
|
||||||
|
|
|
@ -385,19 +385,21 @@ GPUDevice::AdapterInfoList VulkanDevice::GetAdapterList()
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VulkanDevice::SelectDeviceExtensions(ExtensionList* extension_list, bool enable_surface)
|
bool VulkanDevice::SelectDeviceExtensions(ExtensionList* extension_list, bool enable_surface, Error* error)
|
||||||
{
|
{
|
||||||
u32 extension_count = 0;
|
u32 extension_count = 0;
|
||||||
VkResult res = vkEnumerateDeviceExtensionProperties(m_physical_device, nullptr, &extension_count, nullptr);
|
VkResult res = vkEnumerateDeviceExtensionProperties(m_physical_device, nullptr, &extension_count, nullptr);
|
||||||
if (res != VK_SUCCESS)
|
if (res != VK_SUCCESS)
|
||||||
{
|
{
|
||||||
LOG_VULKAN_ERROR(res, "vkEnumerateDeviceExtensionProperties failed: ");
|
LOG_VULKAN_ERROR(res, "vkEnumerateDeviceExtensionProperties failed: ");
|
||||||
|
Vulkan::SetErrorObject(error, "vkEnumerateDeviceExtensionProperties failed: ", res);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (extension_count == 0)
|
if (extension_count == 0)
|
||||||
{
|
{
|
||||||
ERROR_LOG("Vulkan: No extensions supported by device.");
|
ERROR_LOG("No extensions supported by device.");
|
||||||
|
Error::SetStringView(error, "No extensions supported by device.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -423,7 +425,10 @@ bool VulkanDevice::SelectDeviceExtensions(ExtensionList* extension_list, bool en
|
||||||
}
|
}
|
||||||
|
|
||||||
if (required)
|
if (required)
|
||||||
|
{
|
||||||
ERROR_LOG("Vulkan: Missing required extension {}.", name);
|
ERROR_LOG("Vulkan: Missing required extension {}.", name);
|
||||||
|
Error::SetStringFmt(error, "Missing required extension {}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
@ -466,6 +471,11 @@ bool VulkanDevice::SelectDeviceExtensions(ExtensionList* extension_list, bool en
|
||||||
m_optional_extensions.vk_ext_swapchain_maintenance1 &&
|
m_optional_extensions.vk_ext_swapchain_maintenance1 &&
|
||||||
SupportsExtension(VK_EXT_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME, false);
|
SupportsExtension(VK_EXT_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME, false);
|
||||||
|
|
||||||
|
// Dynamic rendering isn't strictly needed for FSI, but we want it with framebufferless rendering.
|
||||||
|
m_optional_extensions.vk_ext_fragment_shader_interlock =
|
||||||
|
m_optional_extensions.vk_khr_dynamic_rendering &&
|
||||||
|
SupportsExtension(VK_EXT_FRAGMENT_SHADER_INTERLOCK_EXTENSION_NAME, false);
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
m_optional_extensions.vk_ext_full_screen_exclusive =
|
m_optional_extensions.vk_ext_full_screen_exclusive =
|
||||||
enable_surface && SupportsExtension(VK_EXT_FULL_SCREEN_EXCLUSIVE_EXTENSION_NAME, false);
|
enable_surface && SupportsExtension(VK_EXT_FULL_SCREEN_EXCLUSIVE_EXTENSION_NAME, false);
|
||||||
|
@ -480,6 +490,7 @@ bool VulkanDevice::SelectDeviceExtensions(ExtensionList* extension_list, bool en
|
||||||
{
|
{
|
||||||
m_optional_extensions.vk_khr_dynamic_rendering = false;
|
m_optional_extensions.vk_khr_dynamic_rendering = false;
|
||||||
m_optional_extensions.vk_khr_dynamic_rendering_local_read = false;
|
m_optional_extensions.vk_khr_dynamic_rendering_local_read = false;
|
||||||
|
m_optional_extensions.vk_ext_fragment_shader_interlock = false;
|
||||||
WARNING_LOG("Disabling VK_KHR_dynamic_rendering on broken mobile driver.");
|
WARNING_LOG("Disabling VK_KHR_dynamic_rendering on broken mobile driver.");
|
||||||
}
|
}
|
||||||
if (m_optional_extensions.vk_khr_push_descriptor)
|
if (m_optional_extensions.vk_khr_push_descriptor)
|
||||||
|
@ -501,29 +512,15 @@ bool VulkanDevice::SelectDeviceExtensions(ExtensionList* extension_list, bool en
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VulkanDevice::SelectDeviceFeatures()
|
bool VulkanDevice::CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer, FeatureMask disabled_features,
|
||||||
{
|
Error* error)
|
||||||
VkPhysicalDeviceFeatures available_features;
|
|
||||||
vkGetPhysicalDeviceFeatures(m_physical_device, &available_features);
|
|
||||||
|
|
||||||
// Enable the features we use.
|
|
||||||
m_device_features.dualSrcBlend = available_features.dualSrcBlend;
|
|
||||||
m_device_features.largePoints = available_features.largePoints;
|
|
||||||
m_device_features.wideLines = available_features.wideLines;
|
|
||||||
m_device_features.samplerAnisotropy = available_features.samplerAnisotropy;
|
|
||||||
m_device_features.sampleRateShading = available_features.sampleRateShading;
|
|
||||||
m_device_features.geometryShader = available_features.geometryShader;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VulkanDevice::CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer)
|
|
||||||
{
|
{
|
||||||
u32 queue_family_count;
|
u32 queue_family_count;
|
||||||
vkGetPhysicalDeviceQueueFamilyProperties(m_physical_device, &queue_family_count, nullptr);
|
vkGetPhysicalDeviceQueueFamilyProperties(m_physical_device, &queue_family_count, nullptr);
|
||||||
if (queue_family_count == 0)
|
if (queue_family_count == 0)
|
||||||
{
|
{
|
||||||
ERROR_LOG("No queue families found on specified vulkan physical device.");
|
ERROR_LOG("No queue families found on specified vulkan physical device.");
|
||||||
|
Error::SetStringView(error, "No queue families found on specified vulkan physical device.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -554,6 +551,7 @@ bool VulkanDevice::CreateDevice(VkSurfaceKHR surface, bool enable_validation_lay
|
||||||
if (res != VK_SUCCESS)
|
if (res != VK_SUCCESS)
|
||||||
{
|
{
|
||||||
LOG_VULKAN_ERROR(res, "vkGetPhysicalDeviceSurfaceSupportKHR failed: ");
|
LOG_VULKAN_ERROR(res, "vkGetPhysicalDeviceSurfaceSupportKHR failed: ");
|
||||||
|
Vulkan::SetErrorObject(error, "vkGetPhysicalDeviceSurfaceSupportKHR failed: ", res);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -572,11 +570,13 @@ bool VulkanDevice::CreateDevice(VkSurfaceKHR surface, bool enable_validation_lay
|
||||||
if (m_graphics_queue_family_index == queue_family_count)
|
if (m_graphics_queue_family_index == queue_family_count)
|
||||||
{
|
{
|
||||||
ERROR_LOG("Vulkan: Failed to find an acceptable graphics queue.");
|
ERROR_LOG("Vulkan: Failed to find an acceptable graphics queue.");
|
||||||
|
Error::SetStringView(error, "Vulkan: Failed to find an acceptable graphics queue.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (surface != VK_NULL_HANDLE && m_present_queue_family_index == queue_family_count)
|
if (surface != VK_NULL_HANDLE && m_present_queue_family_index == queue_family_count)
|
||||||
{
|
{
|
||||||
ERROR_LOG("Vulkan: Failed to find an acceptable present queue.");
|
ERROR_LOG("Vulkan: Failed to find an acceptable present queue.");
|
||||||
|
Error::SetStringView(error, "Vulkan: Failed to find an acceptable present queue.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -610,17 +610,26 @@ bool VulkanDevice::CreateDevice(VkSurfaceKHR surface, bool enable_validation_lay
|
||||||
device_info.pQueueCreateInfos = queue_infos.data();
|
device_info.pQueueCreateInfos = queue_infos.data();
|
||||||
|
|
||||||
ExtensionList enabled_extensions;
|
ExtensionList enabled_extensions;
|
||||||
if (!SelectDeviceExtensions(&enabled_extensions, surface != VK_NULL_HANDLE))
|
if (!SelectDeviceExtensions(&enabled_extensions, surface != VK_NULL_HANDLE, error))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
device_info.enabledExtensionCount = static_cast<uint32_t>(enabled_extensions.size());
|
device_info.enabledExtensionCount = static_cast<uint32_t>(enabled_extensions.size());
|
||||||
device_info.ppEnabledExtensionNames = enabled_extensions.data();
|
device_info.ppEnabledExtensionNames = enabled_extensions.data();
|
||||||
|
|
||||||
// Check for required features before creating.
|
// Check for required features before creating.
|
||||||
if (!SelectDeviceFeatures())
|
VkPhysicalDeviceFeatures available_features;
|
||||||
return false;
|
vkGetPhysicalDeviceFeatures(m_physical_device, &available_features);
|
||||||
|
|
||||||
device_info.pEnabledFeatures = &m_device_features;
|
// Enable the features we use.
|
||||||
|
VkPhysicalDeviceFeatures enabled_features = {};
|
||||||
|
enabled_features.dualSrcBlend = available_features.dualSrcBlend;
|
||||||
|
enabled_features.largePoints = available_features.largePoints;
|
||||||
|
enabled_features.wideLines = available_features.wideLines;
|
||||||
|
enabled_features.samplerAnisotropy = available_features.samplerAnisotropy;
|
||||||
|
enabled_features.sampleRateShading = available_features.sampleRateShading;
|
||||||
|
enabled_features.geometryShader = available_features.geometryShader;
|
||||||
|
enabled_features.fragmentStoresAndAtomics = available_features.fragmentStoresAndAtomics;
|
||||||
|
device_info.pEnabledFeatures = &enabled_features;
|
||||||
|
|
||||||
// Enable debug layer on debug builds
|
// Enable debug layer on debug builds
|
||||||
if (enable_validation_layer)
|
if (enable_validation_layer)
|
||||||
|
@ -639,6 +648,8 @@ bool VulkanDevice::CreateDevice(VkSurfaceKHR surface, bool enable_validation_lay
|
||||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_LOCAL_READ_FEATURES_KHR, nullptr, VK_TRUE};
|
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_LOCAL_READ_FEATURES_KHR, nullptr, VK_TRUE};
|
||||||
VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT swapchain_maintenance1_feature = {
|
VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT swapchain_maintenance1_feature = {
|
||||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT, nullptr, VK_TRUE};
|
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT, nullptr, VK_TRUE};
|
||||||
|
VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT fragment_shader_interlock_feature = {
|
||||||
|
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT, nullptr, VK_FALSE, VK_TRUE, VK_FALSE};
|
||||||
|
|
||||||
if (m_optional_extensions.vk_ext_rasterization_order_attachment_access)
|
if (m_optional_extensions.vk_ext_rasterization_order_attachment_access)
|
||||||
Vulkan::AddPointerToChain(&device_info, &rasterization_order_access_feature);
|
Vulkan::AddPointerToChain(&device_info, &rasterization_order_access_feature);
|
||||||
|
@ -649,12 +660,15 @@ bool VulkanDevice::CreateDevice(VkSurfaceKHR surface, bool enable_validation_lay
|
||||||
Vulkan::AddPointerToChain(&device_info, &dynamic_rendering_feature);
|
Vulkan::AddPointerToChain(&device_info, &dynamic_rendering_feature);
|
||||||
if (m_optional_extensions.vk_khr_dynamic_rendering_local_read)
|
if (m_optional_extensions.vk_khr_dynamic_rendering_local_read)
|
||||||
Vulkan::AddPointerToChain(&device_info, &dynamic_rendering_local_read_feature);
|
Vulkan::AddPointerToChain(&device_info, &dynamic_rendering_local_read_feature);
|
||||||
|
if (m_optional_extensions.vk_ext_fragment_shader_interlock)
|
||||||
|
Vulkan::AddPointerToChain(&device_info, &fragment_shader_interlock_feature);
|
||||||
}
|
}
|
||||||
|
|
||||||
VkResult res = vkCreateDevice(m_physical_device, &device_info, nullptr, &m_device);
|
VkResult res = vkCreateDevice(m_physical_device, &device_info, nullptr, &m_device);
|
||||||
if (res != VK_SUCCESS)
|
if (res != VK_SUCCESS)
|
||||||
{
|
{
|
||||||
LOG_VULKAN_ERROR(res, "vkCreateDevice failed: ");
|
LOG_VULKAN_ERROR(res, "vkCreateDevice failed: ");
|
||||||
|
Vulkan::SetErrorObject(error, "vkCreateDevice failed: ", res);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -677,6 +691,7 @@ bool VulkanDevice::CreateDevice(VkSurfaceKHR surface, bool enable_validation_lay
|
||||||
m_device_properties.limits.timestampPeriod);
|
m_device_properties.limits.timestampPeriod);
|
||||||
|
|
||||||
ProcessDeviceExtensions();
|
ProcessDeviceExtensions();
|
||||||
|
SetFeatures(disabled_features, enabled_features);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -693,6 +708,8 @@ void VulkanDevice::ProcessDeviceExtensions()
|
||||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_LOCAL_READ_FEATURES_KHR, nullptr, VK_FALSE};
|
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_LOCAL_READ_FEATURES_KHR, nullptr, VK_FALSE};
|
||||||
VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT swapchain_maintenance1_feature = {
|
VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT swapchain_maintenance1_feature = {
|
||||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT, nullptr, VK_FALSE};
|
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT, nullptr, VK_FALSE};
|
||||||
|
VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT fragment_shader_interlock_feature = {
|
||||||
|
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT, nullptr, VK_FALSE, VK_FALSE, VK_FALSE};
|
||||||
|
|
||||||
// add in optional feature structs
|
// add in optional feature structs
|
||||||
if (m_optional_extensions.vk_ext_rasterization_order_attachment_access)
|
if (m_optional_extensions.vk_ext_rasterization_order_attachment_access)
|
||||||
|
@ -704,6 +721,8 @@ void VulkanDevice::ProcessDeviceExtensions()
|
||||||
Vulkan::AddPointerToChain(&features2, &dynamic_rendering_feature);
|
Vulkan::AddPointerToChain(&features2, &dynamic_rendering_feature);
|
||||||
if (m_optional_extensions.vk_khr_dynamic_rendering_local_read)
|
if (m_optional_extensions.vk_khr_dynamic_rendering_local_read)
|
||||||
Vulkan::AddPointerToChain(&features2, &dynamic_rendering_local_read_feature);
|
Vulkan::AddPointerToChain(&features2, &dynamic_rendering_local_read_feature);
|
||||||
|
if (m_optional_extensions.vk_ext_fragment_shader_interlock)
|
||||||
|
Vulkan::AddPointerToChain(&features2, &fragment_shader_interlock_feature);
|
||||||
}
|
}
|
||||||
|
|
||||||
// we might not have VK_KHR_get_physical_device_properties2...
|
// we might not have VK_KHR_get_physical_device_properties2...
|
||||||
|
@ -738,6 +757,9 @@ void VulkanDevice::ProcessDeviceExtensions()
|
||||||
m_optional_extensions.vk_khr_dynamic_rendering &= (dynamic_rendering_feature.dynamicRendering == VK_TRUE);
|
m_optional_extensions.vk_khr_dynamic_rendering &= (dynamic_rendering_feature.dynamicRendering == VK_TRUE);
|
||||||
m_optional_extensions.vk_khr_dynamic_rendering_local_read &=
|
m_optional_extensions.vk_khr_dynamic_rendering_local_read &=
|
||||||
(dynamic_rendering_local_read_feature.dynamicRenderingLocalRead == VK_TRUE);
|
(dynamic_rendering_local_read_feature.dynamicRenderingLocalRead == VK_TRUE);
|
||||||
|
m_optional_extensions.vk_ext_fragment_shader_interlock &=
|
||||||
|
(m_optional_extensions.vk_khr_dynamic_rendering &&
|
||||||
|
fragment_shader_interlock_feature.fragmentShaderPixelInterlock == VK_TRUE);
|
||||||
|
|
||||||
VkPhysicalDeviceProperties2 properties2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, nullptr, {}};
|
VkPhysicalDeviceProperties2 properties2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, nullptr, {}};
|
||||||
VkPhysicalDevicePushDescriptorPropertiesKHR push_descriptor_properties = {
|
VkPhysicalDevicePushDescriptorPropertiesKHR push_descriptor_properties = {
|
||||||
|
@ -769,6 +791,8 @@ void VulkanDevice::ProcessDeviceExtensions()
|
||||||
INFO_LOG("VK_EXT_external_memory_host is {}",
|
INFO_LOG("VK_EXT_external_memory_host is {}",
|
||||||
m_optional_extensions.vk_ext_external_memory_host ? "supported" : "NOT supported");
|
m_optional_extensions.vk_ext_external_memory_host ? "supported" : "NOT supported");
|
||||||
INFO_LOG("VK_EXT_memory_budget is {}", m_optional_extensions.vk_ext_memory_budget ? "supported" : "NOT supported");
|
INFO_LOG("VK_EXT_memory_budget is {}", m_optional_extensions.vk_ext_memory_budget ? "supported" : "NOT supported");
|
||||||
|
INFO_LOG("VK_EXT_fragment_shader_interlock is {}",
|
||||||
|
m_optional_extensions.vk_ext_fragment_shader_interlock ? "supported" : "NOT supported");
|
||||||
INFO_LOG("VK_EXT_rasterization_order_attachment_access is {}",
|
INFO_LOG("VK_EXT_rasterization_order_attachment_access is {}",
|
||||||
m_optional_extensions.vk_ext_rasterization_order_attachment_access ? "supported" : "NOT supported");
|
m_optional_extensions.vk_ext_rasterization_order_attachment_access ? "supported" : "NOT supported");
|
||||||
INFO_LOG("VK_EXT_swapchain_maintenance1 is {}",
|
INFO_LOG("VK_EXT_swapchain_maintenance1 is {}",
|
||||||
|
@ -2046,15 +2070,9 @@ bool VulkanDevice::CreateDevice(std::string_view adapter, bool threaded_presenta
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempt to create the device.
|
// Attempt to create the device.
|
||||||
if (!CreateDevice(surface, enable_validation_layer))
|
if (!CreateDevice(surface, enable_validation_layer, disabled_features, error))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!CheckFeatures(disabled_features))
|
|
||||||
{
|
|
||||||
Error::SetStringView(error, "Your GPU does not support the required Vulkan features.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// And critical resources.
|
// And critical resources.
|
||||||
if (!CreateAllocator() || !CreatePersistentDescriptorPool() || !CreateCommandBuffers() || !CreatePipelineLayouts())
|
if (!CreateAllocator() || !CreatePersistentDescriptorPool() || !CreateCommandBuffers() || !CreatePipelineLayouts())
|
||||||
return false;
|
return false;
|
||||||
|
@ -2576,14 +2594,13 @@ u32 VulkanDevice::GetMaxMultisamples(VkPhysicalDevice physical_device, const VkP
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VulkanDevice::CheckFeatures(FeatureMask disabled_features)
|
void VulkanDevice::SetFeatures(FeatureMask disabled_features, const VkPhysicalDeviceFeatures& vk_features)
|
||||||
{
|
{
|
||||||
m_max_texture_size =
|
m_max_texture_size =
|
||||||
std::min(m_device_properties.limits.maxImageDimension2D, m_device_properties.limits.maxFramebufferWidth);
|
std::min(m_device_properties.limits.maxImageDimension2D, m_device_properties.limits.maxFramebufferWidth);
|
||||||
m_max_multisamples = GetMaxMultisamples(m_physical_device, m_device_properties);
|
m_max_multisamples = GetMaxMultisamples(m_physical_device, m_device_properties);
|
||||||
|
|
||||||
m_features.dual_source_blend =
|
m_features.dual_source_blend = !(disabled_features & FEATURE_MASK_DUAL_SOURCE_BLEND) && vk_features.dualSrcBlend;
|
||||||
!(disabled_features & FEATURE_MASK_DUAL_SOURCE_BLEND) && m_device_features.dualSrcBlend;
|
|
||||||
m_features.framebuffer_fetch =
|
m_features.framebuffer_fetch =
|
||||||
!(disabled_features & (FEATURE_MASK_FEEDBACK_LOOPS | FEATURE_MASK_FRAMEBUFFER_FETCH)) &&
|
!(disabled_features & (FEATURE_MASK_FEEDBACK_LOOPS | FEATURE_MASK_FRAMEBUFFER_FETCH)) &&
|
||||||
m_optional_extensions.vk_ext_rasterization_order_attachment_access;
|
m_optional_extensions.vk_ext_rasterization_order_attachment_access;
|
||||||
|
@ -2593,7 +2610,7 @@ bool VulkanDevice::CheckFeatures(FeatureMask disabled_features)
|
||||||
|
|
||||||
m_features.noperspective_interpolation = true;
|
m_features.noperspective_interpolation = true;
|
||||||
m_features.texture_copy_to_self = !(disabled_features & FEATURE_MASK_TEXTURE_COPY_TO_SELF);
|
m_features.texture_copy_to_self = !(disabled_features & FEATURE_MASK_TEXTURE_COPY_TO_SELF);
|
||||||
m_features.per_sample_shading = m_device_features.sampleRateShading;
|
m_features.per_sample_shading = vk_features.sampleRateShading;
|
||||||
m_features.supports_texture_buffers = !(disabled_features & FEATURE_MASK_TEXTURE_BUFFERS);
|
m_features.supports_texture_buffers = !(disabled_features & FEATURE_MASK_TEXTURE_BUFFERS);
|
||||||
m_features.feedback_loops = !(disabled_features & FEATURE_MASK_FEEDBACK_LOOPS);
|
m_features.feedback_loops = !(disabled_features & FEATURE_MASK_FEEDBACK_LOOPS);
|
||||||
|
|
||||||
|
@ -2612,8 +2629,7 @@ bool VulkanDevice::CheckFeatures(FeatureMask disabled_features)
|
||||||
if (m_features.texture_buffers_emulated_with_ssbo)
|
if (m_features.texture_buffers_emulated_with_ssbo)
|
||||||
WARNING_LOG("Emulating texture buffers with SSBOs.");
|
WARNING_LOG("Emulating texture buffers with SSBOs.");
|
||||||
|
|
||||||
m_features.geometry_shaders =
|
m_features.geometry_shaders = !(disabled_features & FEATURE_MASK_GEOMETRY_SHADERS) && vk_features.geometryShader;
|
||||||
!(disabled_features & FEATURE_MASK_GEOMETRY_SHADERS) && m_device_features.geometryShader;
|
|
||||||
|
|
||||||
m_features.partial_msaa_resolve = true;
|
m_features.partial_msaa_resolve = true;
|
||||||
m_features.memory_import = m_optional_extensions.vk_ext_external_memory_host;
|
m_features.memory_import = m_optional_extensions.vk_ext_external_memory_host;
|
||||||
|
@ -2621,8 +2637,9 @@ bool VulkanDevice::CheckFeatures(FeatureMask disabled_features)
|
||||||
m_features.shader_cache = true;
|
m_features.shader_cache = true;
|
||||||
m_features.pipeline_cache = true;
|
m_features.pipeline_cache = true;
|
||||||
m_features.prefer_unused_textures = true;
|
m_features.prefer_unused_textures = true;
|
||||||
|
m_features.raster_order_views =
|
||||||
return true;
|
(!(disabled_features & FEATURE_MASK_RASTER_ORDER_VIEWS) && vk_features.fragmentStoresAndAtomics &&
|
||||||
|
m_optional_extensions.vk_ext_fragment_shader_interlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanDevice::CopyTextureRegion(GPUTexture* dst, u32 dst_x, u32 dst_y, u32 dst_layer, u32 dst_level,
|
void VulkanDevice::CopyTextureRegion(GPUTexture* dst, u32 dst_x, u32 dst_y, u32 dst_layer, u32 dst_level,
|
||||||
|
@ -2928,7 +2945,7 @@ void VulkanDevice::UnmapUniformBuffer(u32 size)
|
||||||
|
|
||||||
bool VulkanDevice::CreateNullTexture()
|
bool VulkanDevice::CreateNullTexture()
|
||||||
{
|
{
|
||||||
m_null_texture = VulkanTexture::Create(1, 1, 1, 1, 1, GPUTexture::Type::RenderTarget, GPUTexture::Format::RGBA8,
|
m_null_texture = VulkanTexture::Create(1, 1, 1, 1, 1, GPUTexture::Type::RWTexture, GPUTexture::Format::RGBA8,
|
||||||
VK_FORMAT_R8G8B8A8_UNORM);
|
VK_FORMAT_R8G8B8A8_UNORM);
|
||||||
if (!m_null_texture)
|
if (!m_null_texture)
|
||||||
return false;
|
return false;
|
||||||
|
@ -2948,10 +2965,7 @@ bool VulkanDevice::CreateNullTexture()
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (u32 i = 0; i < MAX_TEXTURE_SAMPLERS; i++)
|
for (u32 i = 0; i < MAX_TEXTURE_SAMPLERS; i++)
|
||||||
{
|
|
||||||
m_current_textures[i] = m_null_texture.get();
|
|
||||||
m_current_samplers[i] = point_sampler;
|
m_current_samplers[i] = point_sampler;
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -3005,59 +3019,89 @@ bool VulkanDevice::CreatePipelineLayouts()
|
||||||
Vulkan::SetObjectName(m_device, m_feedback_loop_ds_layout, "Feedback Loop Descriptor Set Layout");
|
Vulkan::SetObjectName(m_device, m_feedback_loop_ds_layout, "Feedback Loop Descriptor Set Layout");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_features.raster_order_views)
|
||||||
{
|
{
|
||||||
VkPipelineLayout& pl = m_pipeline_layouts[static_cast<u8>(GPUPipeline::Layout::SingleTextureAndUBO)];
|
for (u32 i = 0; i < MAX_IMAGE_RENDER_TARGETS; i++)
|
||||||
plb.AddDescriptorSet(m_ubo_ds_layout);
|
dslb.AddBinding(i, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
plb.AddDescriptorSet(m_single_texture_ds_layout);
|
if ((m_rov_ds_layout = dslb.Create(m_device)) == VK_NULL_HANDLE)
|
||||||
// TODO: REMOVE ME
|
|
||||||
if (m_features.feedback_loops)
|
|
||||||
plb.AddDescriptorSet(m_feedback_loop_ds_layout);
|
|
||||||
if ((pl = plb.Create(m_device)) == VK_NULL_HANDLE)
|
|
||||||
return false;
|
return false;
|
||||||
Vulkan::SetObjectName(m_device, pl, "Single Texture + UBO Pipeline Layout");
|
Vulkan::SetObjectName(m_device, m_feedback_loop_ds_layout, "ROV Descriptor Set Layout");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (u32 type = 0; type < 3; type++)
|
||||||
{
|
{
|
||||||
VkPipelineLayout& pl = m_pipeline_layouts[static_cast<u8>(GPUPipeline::Layout::SingleTextureAndPushConstants)];
|
const bool feedback_loop = (type == 1);
|
||||||
plb.AddDescriptorSet(m_single_texture_ds_layout);
|
const bool rov = (type == 2);
|
||||||
// TODO: REMOVE ME
|
if ((feedback_loop && !m_features.feedback_loops) || (rov && !m_features.raster_order_views))
|
||||||
if (m_features.feedback_loops)
|
continue;
|
||||||
plb.AddDescriptorSet(m_feedback_loop_ds_layout);
|
|
||||||
plb.AddPushConstants(UNIFORM_PUSH_CONSTANTS_STAGES, 0, UNIFORM_PUSH_CONSTANTS_SIZE);
|
|
||||||
if ((pl = plb.Create(m_device)) == VK_NULL_HANDLE)
|
|
||||||
return false;
|
|
||||||
Vulkan::SetObjectName(m_device, pl, "Single Texture Pipeline Layout");
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
VkPipelineLayout& pl =
|
VkPipelineLayout& pl = m_pipeline_layouts[type][static_cast<u8>(GPUPipeline::Layout::SingleTextureAndUBO)];
|
||||||
m_pipeline_layouts[static_cast<u8>(GPUPipeline::Layout::SingleTextureBufferAndPushConstants)];
|
plb.AddDescriptorSet(m_ubo_ds_layout);
|
||||||
plb.AddDescriptorSet(m_single_texture_buffer_ds_layout);
|
plb.AddDescriptorSet(m_single_texture_ds_layout);
|
||||||
// TODO: REMOVE ME
|
if (feedback_loop)
|
||||||
if (m_features.feedback_loops)
|
plb.AddDescriptorSet(m_feedback_loop_ds_layout);
|
||||||
plb.AddDescriptorSet(m_feedback_loop_ds_layout);
|
else if (rov)
|
||||||
plb.AddPushConstants(UNIFORM_PUSH_CONSTANTS_STAGES, 0, UNIFORM_PUSH_CONSTANTS_SIZE);
|
plb.AddDescriptorSet(m_rov_ds_layout);
|
||||||
if ((pl = plb.Create(m_device)) == VK_NULL_HANDLE)
|
if ((pl = plb.Create(m_device)) == VK_NULL_HANDLE)
|
||||||
return false;
|
return false;
|
||||||
Vulkan::SetObjectName(m_device, pl, "Single Texture Buffer + UBO Pipeline Layout");
|
Vulkan::SetObjectName(m_device, pl, "Single Texture + UBO Pipeline Layout");
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
VkPipelineLayout& pl = m_pipeline_layouts[static_cast<u8>(GPUPipeline::Layout::MultiTextureAndUBO)];
|
VkPipelineLayout& pl =
|
||||||
plb.AddDescriptorSet(m_ubo_ds_layout);
|
m_pipeline_layouts[type][static_cast<u8>(GPUPipeline::Layout::SingleTextureAndPushConstants)];
|
||||||
plb.AddDescriptorSet(m_multi_texture_ds_layout);
|
plb.AddDescriptorSet(m_single_texture_ds_layout);
|
||||||
if ((pl = plb.Create(m_device)) == VK_NULL_HANDLE)
|
if (feedback_loop)
|
||||||
return false;
|
plb.AddDescriptorSet(m_feedback_loop_ds_layout);
|
||||||
Vulkan::SetObjectName(m_device, pl, "Multi Texture + UBO Pipeline Layout");
|
else if (rov)
|
||||||
}
|
plb.AddDescriptorSet(m_rov_ds_layout);
|
||||||
|
plb.AddPushConstants(UNIFORM_PUSH_CONSTANTS_STAGES, 0, UNIFORM_PUSH_CONSTANTS_SIZE);
|
||||||
|
if ((pl = plb.Create(m_device)) == VK_NULL_HANDLE)
|
||||||
|
return false;
|
||||||
|
Vulkan::SetObjectName(m_device, pl, "Single Texture Pipeline Layout");
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
VkPipelineLayout& pl = m_pipeline_layouts[static_cast<u8>(GPUPipeline::Layout::MultiTextureAndPushConstants)];
|
VkPipelineLayout& pl =
|
||||||
plb.AddDescriptorSet(m_multi_texture_ds_layout);
|
m_pipeline_layouts[type][static_cast<u8>(GPUPipeline::Layout::SingleTextureBufferAndPushConstants)];
|
||||||
plb.AddPushConstants(UNIFORM_PUSH_CONSTANTS_STAGES, 0, UNIFORM_PUSH_CONSTANTS_SIZE);
|
plb.AddDescriptorSet(m_single_texture_buffer_ds_layout);
|
||||||
if ((pl = plb.Create(m_device)) == VK_NULL_HANDLE)
|
if (feedback_loop)
|
||||||
return false;
|
plb.AddDescriptorSet(m_feedback_loop_ds_layout);
|
||||||
Vulkan::SetObjectName(m_device, pl, "Multi Texture Pipeline Layout");
|
else if (rov)
|
||||||
|
plb.AddDescriptorSet(m_rov_ds_layout);
|
||||||
|
plb.AddPushConstants(UNIFORM_PUSH_CONSTANTS_STAGES, 0, UNIFORM_PUSH_CONSTANTS_SIZE);
|
||||||
|
if ((pl = plb.Create(m_device)) == VK_NULL_HANDLE)
|
||||||
|
return false;
|
||||||
|
Vulkan::SetObjectName(m_device, pl, "Single Texture Buffer + UBO Pipeline Layout");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
VkPipelineLayout& pl = m_pipeline_layouts[type][static_cast<u8>(GPUPipeline::Layout::MultiTextureAndUBO)];
|
||||||
|
plb.AddDescriptorSet(m_ubo_ds_layout);
|
||||||
|
plb.AddDescriptorSet(m_multi_texture_ds_layout);
|
||||||
|
if (feedback_loop)
|
||||||
|
plb.AddDescriptorSet(m_feedback_loop_ds_layout);
|
||||||
|
else if (rov)
|
||||||
|
plb.AddDescriptorSet(m_rov_ds_layout);
|
||||||
|
if ((pl = plb.Create(m_device)) == VK_NULL_HANDLE)
|
||||||
|
return false;
|
||||||
|
Vulkan::SetObjectName(m_device, pl, "Multi Texture + UBO Pipeline Layout");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
VkPipelineLayout& pl =
|
||||||
|
m_pipeline_layouts[type][static_cast<u8>(GPUPipeline::Layout::MultiTextureAndPushConstants)];
|
||||||
|
plb.AddDescriptorSet(m_multi_texture_ds_layout);
|
||||||
|
plb.AddPushConstants(UNIFORM_PUSH_CONSTANTS_STAGES, 0, UNIFORM_PUSH_CONSTANTS_SIZE);
|
||||||
|
if (feedback_loop)
|
||||||
|
plb.AddDescriptorSet(m_feedback_loop_ds_layout);
|
||||||
|
else if (rov)
|
||||||
|
plb.AddDescriptorSet(m_rov_ds_layout);
|
||||||
|
if ((pl = plb.Create(m_device)) == VK_NULL_HANDLE)
|
||||||
|
return false;
|
||||||
|
Vulkan::SetObjectName(m_device, pl, "Multi Texture Pipeline Layout");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -3065,14 +3109,13 @@ bool VulkanDevice::CreatePipelineLayouts()
|
||||||
|
|
||||||
void VulkanDevice::DestroyPipelineLayouts()
|
void VulkanDevice::DestroyPipelineLayouts()
|
||||||
{
|
{
|
||||||
for (VkPipelineLayout& pl : m_pipeline_layouts)
|
m_pipeline_layouts.enumerate([this](auto& pl) {
|
||||||
{
|
|
||||||
if (pl != VK_NULL_HANDLE)
|
if (pl != VK_NULL_HANDLE)
|
||||||
{
|
{
|
||||||
vkDestroyPipelineLayout(m_device, pl, nullptr);
|
vkDestroyPipelineLayout(m_device, pl, nullptr);
|
||||||
pl = VK_NULL_HANDLE;
|
pl = VK_NULL_HANDLE;
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
auto destroy_dsl = [this](VkDescriptorSetLayout& l) {
|
auto destroy_dsl = [this](VkDescriptorSetLayout& l) {
|
||||||
if (l != VK_NULL_HANDLE)
|
if (l != VK_NULL_HANDLE)
|
||||||
|
@ -3081,6 +3124,7 @@ void VulkanDevice::DestroyPipelineLayouts()
|
||||||
l = VK_NULL_HANDLE;
|
l = VK_NULL_HANDLE;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
destroy_dsl(m_rov_ds_layout);
|
||||||
destroy_dsl(m_feedback_loop_ds_layout);
|
destroy_dsl(m_feedback_loop_ds_layout);
|
||||||
destroy_dsl(m_multi_texture_ds_layout);
|
destroy_dsl(m_multi_texture_ds_layout);
|
||||||
destroy_dsl(m_single_texture_buffer_ds_layout);
|
destroy_dsl(m_single_texture_buffer_ds_layout);
|
||||||
|
@ -3222,10 +3266,13 @@ bool VulkanDevice::TryImportHostMemory(void* data, size_t data_size, VkBufferUsa
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanDevice::SetRenderTargets(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds,
|
void VulkanDevice::SetRenderTargets(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds,
|
||||||
GPUPipeline::RenderPassFlag feedback_loop)
|
GPUPipeline::RenderPassFlag flags)
|
||||||
{
|
{
|
||||||
bool changed = (m_num_current_render_targets != num_rts || m_current_depth_target != ds ||
|
const bool changed_layout =
|
||||||
m_current_feedback_loop != feedback_loop);
|
(m_current_render_pass_flags & (GPUPipeline::ColorFeedbackLoop | GPUPipeline::BindRenderTargetsAsImages)) !=
|
||||||
|
(flags & (GPUPipeline::ColorFeedbackLoop | GPUPipeline::BindRenderTargetsAsImages));
|
||||||
|
bool changed =
|
||||||
|
(m_num_current_render_targets != num_rts || m_current_depth_target != ds || m_current_render_pass_flags != flags);
|
||||||
bool needs_ds_clear = (ds && ds->IsClearedOrInvalidated());
|
bool needs_ds_clear = (ds && ds->IsClearedOrInvalidated());
|
||||||
bool needs_rt_clear = false;
|
bool needs_rt_clear = false;
|
||||||
|
|
||||||
|
@ -3240,7 +3287,7 @@ void VulkanDevice::SetRenderTargets(GPUTexture* const* rts, u32 num_rts, GPUText
|
||||||
for (u32 i = num_rts; i < m_num_current_render_targets; i++)
|
for (u32 i = num_rts; i < m_num_current_render_targets; i++)
|
||||||
m_current_render_targets[i] = nullptr;
|
m_current_render_targets[i] = nullptr;
|
||||||
m_num_current_render_targets = Truncate8(num_rts);
|
m_num_current_render_targets = Truncate8(num_rts);
|
||||||
m_current_feedback_loop = feedback_loop;
|
m_current_render_pass_flags = flags;
|
||||||
|
|
||||||
if (changed)
|
if (changed)
|
||||||
{
|
{
|
||||||
|
@ -3253,12 +3300,12 @@ void VulkanDevice::SetRenderTargets(GPUTexture* const* rts, u32 num_rts, GPUText
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_optional_extensions.vk_khr_dynamic_rendering || ((feedback_loop & GPUPipeline::ColorFeedbackLoop) &&
|
if (!m_optional_extensions.vk_khr_dynamic_rendering ||
|
||||||
!m_optional_extensions.vk_khr_dynamic_rendering_local_read))
|
((flags & GPUPipeline::ColorFeedbackLoop) && !m_optional_extensions.vk_khr_dynamic_rendering_local_read))
|
||||||
{
|
{
|
||||||
m_current_framebuffer = m_framebuffer_manager.Lookup(
|
m_current_framebuffer = m_framebuffer_manager.Lookup(
|
||||||
(m_num_current_render_targets > 0) ? reinterpret_cast<GPUTexture**>(m_current_render_targets.data()) : nullptr,
|
(m_num_current_render_targets > 0) ? reinterpret_cast<GPUTexture**>(m_current_render_targets.data()) : nullptr,
|
||||||
m_num_current_render_targets, m_current_depth_target, feedback_loop);
|
m_num_current_render_targets, m_current_depth_target, flags);
|
||||||
if (m_current_framebuffer == VK_NULL_HANDLE)
|
if (m_current_framebuffer == VK_NULL_HANDLE)
|
||||||
{
|
{
|
||||||
ERROR_LOG("Failed to create framebuffer");
|
ERROR_LOG("Failed to create framebuffer");
|
||||||
|
@ -3266,8 +3313,10 @@ void VulkanDevice::SetRenderTargets(GPUTexture* const* rts, u32 num_rts, GPUText
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_dirty_flags = (m_dirty_flags & ~DIRTY_FLAG_INPUT_ATTACHMENT) |
|
m_dirty_flags = (m_dirty_flags & ~DIRTY_FLAG_INPUT_ATTACHMENT) | (changed_layout ? DIRTY_FLAG_PIPELINE_LAYOUT : 0) |
|
||||||
((feedback_loop & GPUPipeline::ColorFeedbackLoop) ? DIRTY_FLAG_INPUT_ATTACHMENT : 0);
|
((flags & (GPUPipeline::ColorFeedbackLoop | GPUPipeline::BindRenderTargetsAsImages)) ?
|
||||||
|
DIRTY_FLAG_INPUT_ATTACHMENT :
|
||||||
|
0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: This could use vkCmdClearAttachments() instead.
|
// TODO: This could use vkCmdClearAttachments() instead.
|
||||||
|
@ -3285,11 +3334,14 @@ void VulkanDevice::BeginRenderPass()
|
||||||
// All textures should be in shader read only optimal already, but just in case..
|
// All textures should be in shader read only optimal already, but just in case..
|
||||||
const u32 num_textures = GetActiveTexturesForLayout(m_current_pipeline_layout);
|
const u32 num_textures = GetActiveTexturesForLayout(m_current_pipeline_layout);
|
||||||
for (u32 i = 0; i < num_textures; i++)
|
for (u32 i = 0; i < num_textures; i++)
|
||||||
m_current_textures[i]->TransitionToLayout(VulkanTexture::Layout::ShaderReadOnly);
|
{
|
||||||
|
if (m_current_textures[i])
|
||||||
|
m_current_textures[i]->TransitionToLayout(VulkanTexture::Layout::ShaderReadOnly);
|
||||||
|
}
|
||||||
|
|
||||||
// NVIDIA drivers appear to return random garbage when sampling the RT via a feedback loop, if the load op for
|
// NVIDIA drivers appear to return random garbage when sampling the RT via a feedback loop, if the load op for
|
||||||
// the render pass is CLEAR. Using vkCmdClearAttachments() doesn't work, so we have to clear the image instead.
|
// the render pass is CLEAR. Using vkCmdClearAttachments() doesn't work, so we have to clear the image instead.
|
||||||
if (m_current_feedback_loop & GPUPipeline::ColorFeedbackLoop)
|
if (m_current_render_pass_flags & GPUPipeline::ColorFeedbackLoop && IsDeviceNVIDIA())
|
||||||
{
|
{
|
||||||
for (u32 i = 0; i < m_num_current_render_targets; i++)
|
for (u32 i = 0; i < m_num_current_render_targets; i++)
|
||||||
{
|
{
|
||||||
|
@ -3298,8 +3350,9 @@ void VulkanDevice::BeginRenderPass()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_optional_extensions.vk_khr_dynamic_rendering && (m_optional_extensions.vk_khr_dynamic_rendering_local_read ||
|
if (m_optional_extensions.vk_khr_dynamic_rendering &&
|
||||||
!(m_current_feedback_loop & GPUPipeline::ColorFeedbackLoop)))
|
(m_optional_extensions.vk_khr_dynamic_rendering_local_read ||
|
||||||
|
!(m_current_render_pass_flags & GPUPipeline::ColorFeedbackLoop)))
|
||||||
{
|
{
|
||||||
VkRenderingInfoKHR ri = {
|
VkRenderingInfoKHR ri = {
|
||||||
VK_STRUCTURE_TYPE_RENDERING_INFO_KHR, nullptr, 0u, {}, 1u, 0u, 0u, nullptr, nullptr, nullptr};
|
VK_STRUCTURE_TYPE_RENDERING_INFO_KHR, nullptr, 0u, {}, 1u, 0u, 0u, nullptr, nullptr, nullptr};
|
||||||
|
@ -3309,35 +3362,51 @@ void VulkanDevice::BeginRenderPass()
|
||||||
|
|
||||||
if (m_num_current_render_targets > 0 || m_current_depth_target)
|
if (m_num_current_render_targets > 0 || m_current_depth_target)
|
||||||
{
|
{
|
||||||
ri.colorAttachmentCount = m_num_current_render_targets;
|
if (!(m_current_render_pass_flags & GPUPipeline::BindRenderTargetsAsImages))
|
||||||
ri.pColorAttachments = (m_num_current_render_targets > 0) ? attachments.data() : nullptr;
|
|
||||||
|
|
||||||
// set up clear values and transition targets
|
|
||||||
for (u32 i = 0; i < m_num_current_render_targets; i++)
|
|
||||||
{
|
{
|
||||||
VulkanTexture* const rt = static_cast<VulkanTexture*>(m_current_render_targets[i]);
|
ri.colorAttachmentCount = m_num_current_render_targets;
|
||||||
rt->TransitionToLayout((m_current_feedback_loop & GPUPipeline::ColorFeedbackLoop) ?
|
ri.pColorAttachments = (m_num_current_render_targets > 0) ? attachments.data() : nullptr;
|
||||||
VulkanTexture::Layout::FeedbackLoop :
|
|
||||||
VulkanTexture::Layout::ColorAttachment);
|
|
||||||
rt->SetUseFenceCounter(GetCurrentFenceCounter());
|
|
||||||
|
|
||||||
VkRenderingAttachmentInfo& ai = attachments[i];
|
// set up clear values and transition targets
|
||||||
ai.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR;
|
for (u32 i = 0; i < m_num_current_render_targets; i++)
|
||||||
ai.pNext = nullptr;
|
|
||||||
ai.imageView = rt->GetView();
|
|
||||||
ai.imageLayout = rt->GetVkLayout();
|
|
||||||
ai.resolveMode = VK_RESOLVE_MODE_NONE_KHR;
|
|
||||||
ai.resolveImageView = VK_NULL_HANDLE;
|
|
||||||
ai.resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
||||||
ai.loadOp = GetLoadOpForTexture(rt);
|
|
||||||
ai.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
|
||||||
|
|
||||||
if (rt->GetState() == GPUTexture::State::Cleared)
|
|
||||||
{
|
{
|
||||||
std::memcpy(ai.clearValue.color.float32, rt->GetUNormClearColor().data(),
|
VulkanTexture* const rt = static_cast<VulkanTexture*>(m_current_render_targets[i]);
|
||||||
sizeof(ai.clearValue.color.float32));
|
rt->TransitionToLayout((m_current_render_pass_flags & GPUPipeline::ColorFeedbackLoop) ?
|
||||||
|
VulkanTexture::Layout::FeedbackLoop :
|
||||||
|
VulkanTexture::Layout::ColorAttachment);
|
||||||
|
rt->SetUseFenceCounter(GetCurrentFenceCounter());
|
||||||
|
|
||||||
|
VkRenderingAttachmentInfo& ai = attachments[i];
|
||||||
|
ai.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR;
|
||||||
|
ai.pNext = nullptr;
|
||||||
|
ai.imageView = rt->GetView();
|
||||||
|
ai.imageLayout = rt->GetVkLayout();
|
||||||
|
ai.resolveMode = VK_RESOLVE_MODE_NONE_KHR;
|
||||||
|
ai.resolveImageView = VK_NULL_HANDLE;
|
||||||
|
ai.resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
ai.loadOp = GetLoadOpForTexture(rt);
|
||||||
|
ai.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||||
|
|
||||||
|
if (rt->GetState() == GPUTexture::State::Cleared)
|
||||||
|
{
|
||||||
|
std::memcpy(ai.clearValue.color.float32, rt->GetUNormClearColor().data(),
|
||||||
|
sizeof(ai.clearValue.color.float32));
|
||||||
|
}
|
||||||
|
rt->SetState(GPUTexture::State::Dirty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Binding as image, but we still need to clear it.
|
||||||
|
for (u32 i = 0; i < m_num_current_render_targets; i++)
|
||||||
|
{
|
||||||
|
VulkanTexture* rt = m_current_render_targets[i];
|
||||||
|
if (rt->GetState() == GPUTexture::State::Cleared)
|
||||||
|
rt->CommitClear(m_current_command_buffer);
|
||||||
|
rt->SetState(GPUTexture::State::Dirty);
|
||||||
|
rt->TransitionToLayout(VulkanTexture::Layout::ReadWriteImage);
|
||||||
|
rt->SetUseFenceCounter(GetCurrentFenceCounter());
|
||||||
}
|
}
|
||||||
rt->SetState(GPUTexture::State::Dirty);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (VulkanTexture* const ds = m_current_depth_target)
|
if (VulkanTexture* const ds = m_current_depth_target)
|
||||||
|
@ -3396,8 +3465,9 @@ void VulkanDevice::BeginRenderPass()
|
||||||
if (m_current_framebuffer != VK_NULL_HANDLE)
|
if (m_current_framebuffer != VK_NULL_HANDLE)
|
||||||
{
|
{
|
||||||
bi.framebuffer = m_current_framebuffer;
|
bi.framebuffer = m_current_framebuffer;
|
||||||
bi.renderPass = m_current_render_pass = GetRenderPass(
|
bi.renderPass = m_current_render_pass =
|
||||||
m_current_render_targets.data(), m_num_current_render_targets, m_current_depth_target, m_current_feedback_loop);
|
GetRenderPass(m_current_render_targets.data(), m_num_current_render_targets, m_current_depth_target,
|
||||||
|
m_current_render_pass_flags);
|
||||||
if (bi.renderPass == VK_NULL_HANDLE)
|
if (bi.renderPass == VK_NULL_HANDLE)
|
||||||
{
|
{
|
||||||
ERROR_LOG("Failed to create render pass");
|
ERROR_LOG("Failed to create render pass");
|
||||||
|
@ -3416,7 +3486,7 @@ void VulkanDevice::BeginRenderPass()
|
||||||
bi.clearValueCount = i + 1;
|
bi.clearValueCount = i + 1;
|
||||||
}
|
}
|
||||||
rt->SetState(GPUTexture::State::Dirty);
|
rt->SetState(GPUTexture::State::Dirty);
|
||||||
rt->TransitionToLayout((m_current_feedback_loop & GPUPipeline::ColorFeedbackLoop) ?
|
rt->TransitionToLayout((m_current_render_pass_flags & GPUPipeline::ColorFeedbackLoop) ?
|
||||||
VulkanTexture::Layout::FeedbackLoop :
|
VulkanTexture::Layout::FeedbackLoop :
|
||||||
VulkanTexture::Layout::ColorAttachment);
|
VulkanTexture::Layout::ColorAttachment);
|
||||||
rt->SetUseFenceCounter(GetCurrentFenceCounter());
|
rt->SetUseFenceCounter(GetCurrentFenceCounter());
|
||||||
|
@ -3473,7 +3543,10 @@ void VulkanDevice::BeginSwapChainRenderPass()
|
||||||
// All textures should be in shader read only optimal already, but just in case..
|
// All textures should be in shader read only optimal already, but just in case..
|
||||||
const u32 num_textures = GetActiveTexturesForLayout(m_current_pipeline_layout);
|
const u32 num_textures = GetActiveTexturesForLayout(m_current_pipeline_layout);
|
||||||
for (u32 i = 0; i < num_textures; i++)
|
for (u32 i = 0; i < num_textures; i++)
|
||||||
m_current_textures[i]->TransitionToLayout(VulkanTexture::Layout::ShaderReadOnly);
|
{
|
||||||
|
if (m_current_textures[i])
|
||||||
|
m_current_textures[i]->TransitionToLayout(VulkanTexture::Layout::ShaderReadOnly);
|
||||||
|
}
|
||||||
|
|
||||||
if (m_optional_extensions.vk_khr_dynamic_rendering)
|
if (m_optional_extensions.vk_khr_dynamic_rendering)
|
||||||
{
|
{
|
||||||
|
@ -3518,15 +3591,16 @@ void VulkanDevice::BeginSwapChainRenderPass()
|
||||||
vkCmdBeginRenderPass(GetCurrentCommandBuffer(), &rp, VK_SUBPASS_CONTENTS_INLINE);
|
vkCmdBeginRenderPass(GetCurrentCommandBuffer(), &rp, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_dirty_flags |=
|
||||||
|
(m_current_render_pass_flags & (GPUPipeline::ColorFeedbackLoop | GPUPipeline::BindRenderTargetsAsImages)) ?
|
||||||
|
DIRTY_FLAG_PIPELINE_LAYOUT :
|
||||||
|
0;
|
||||||
s_stats.num_render_passes++;
|
s_stats.num_render_passes++;
|
||||||
m_num_current_render_targets = 0;
|
m_num_current_render_targets = 0;
|
||||||
m_current_feedback_loop = GPUPipeline::NoRenderPassFlags;
|
m_current_render_pass_flags = GPUPipeline::NoRenderPassFlags;
|
||||||
std::memset(m_current_render_targets.data(), 0, sizeof(m_current_render_targets));
|
std::memset(m_current_render_targets.data(), 0, sizeof(m_current_render_targets));
|
||||||
m_current_depth_target = nullptr;
|
m_current_depth_target = nullptr;
|
||||||
m_current_framebuffer = VK_NULL_HANDLE;
|
m_current_framebuffer = VK_NULL_HANDLE;
|
||||||
|
|
||||||
// Clear pipeline, it's likely incompatible.
|
|
||||||
m_current_pipeline = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VulkanDevice::InRenderPass()
|
bool VulkanDevice::InRenderPass()
|
||||||
|
@ -3584,8 +3658,8 @@ void VulkanDevice::UnbindPipeline(VulkanPipeline* pl)
|
||||||
|
|
||||||
void VulkanDevice::InvalidateCachedState()
|
void VulkanDevice::InvalidateCachedState()
|
||||||
{
|
{
|
||||||
m_dirty_flags =
|
m_dirty_flags = ALL_DIRTY_STATE |
|
||||||
ALL_DIRTY_STATE | ((m_current_feedback_loop & GPUPipeline::ColorFeedbackLoop) ? DIRTY_FLAG_INPUT_ATTACHMENT : 0);
|
((m_current_render_pass_flags & GPUPipeline::ColorFeedbackLoop) ? DIRTY_FLAG_INPUT_ATTACHMENT : 0);
|
||||||
m_current_render_pass = VK_NULL_HANDLE;
|
m_current_render_pass = VK_NULL_HANDLE;
|
||||||
m_current_pipeline = nullptr;
|
m_current_pipeline = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -3601,9 +3675,18 @@ s32 VulkanDevice::IsRenderTargetBoundIndex(const GPUTexture* tex) const
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VulkanDevice::PipelineLayoutType VulkanDevice::GetPipelineLayoutType(GPUPipeline::RenderPassFlag flags)
|
||||||
|
{
|
||||||
|
return (flags & GPUPipeline::BindRenderTargetsAsImages) ?
|
||||||
|
PipelineLayoutType::BindRenderTargetsAsImages :
|
||||||
|
((flags & GPUPipeline::ColorFeedbackLoop) ? PipelineLayoutType::ColorFeedbackLoop :
|
||||||
|
PipelineLayoutType::Normal);
|
||||||
|
}
|
||||||
|
|
||||||
VkPipelineLayout VulkanDevice::GetCurrentVkPipelineLayout() const
|
VkPipelineLayout VulkanDevice::GetCurrentVkPipelineLayout() const
|
||||||
{
|
{
|
||||||
return m_pipeline_layouts[static_cast<u8>(m_current_pipeline_layout)];
|
return m_pipeline_layouts[static_cast<size_t>(GetPipelineLayoutType(m_current_render_pass_flags))]
|
||||||
|
[static_cast<size_t>(m_current_pipeline_layout)];
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanDevice::SetInitialPipelineState()
|
void VulkanDevice::SetInitialPipelineState()
|
||||||
|
@ -3634,7 +3717,7 @@ void VulkanDevice::SetInitialPipelineState()
|
||||||
|
|
||||||
void VulkanDevice::SetTextureSampler(u32 slot, GPUTexture* texture, GPUSampler* sampler)
|
void VulkanDevice::SetTextureSampler(u32 slot, GPUTexture* texture, GPUSampler* sampler)
|
||||||
{
|
{
|
||||||
VulkanTexture* T = texture ? static_cast<VulkanTexture*>(texture) : m_null_texture.get();
|
VulkanTexture* T = static_cast<VulkanTexture*>(texture);
|
||||||
const VkSampler vsampler = static_cast<VulkanSampler*>(sampler ? sampler : m_nearest_sampler.get())->GetSampler();
|
const VkSampler vsampler = static_cast<VulkanSampler*>(sampler ? sampler : m_nearest_sampler.get())->GetSampler();
|
||||||
if (m_current_textures[slot] != T || m_current_samplers[slot] != vsampler)
|
if (m_current_textures[slot] != T || m_current_samplers[slot] != vsampler)
|
||||||
{
|
{
|
||||||
|
@ -3643,7 +3726,7 @@ void VulkanDevice::SetTextureSampler(u32 slot, GPUTexture* texture, GPUSampler*
|
||||||
m_dirty_flags |= DIRTY_FLAG_TEXTURES_OR_SAMPLERS;
|
m_dirty_flags |= DIRTY_FLAG_TEXTURES_OR_SAMPLERS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (texture)
|
if (T)
|
||||||
{
|
{
|
||||||
T->CommitClear();
|
T->CommitClear();
|
||||||
T->SetUseFenceCounter(GetCurrentFenceCounter());
|
T->SetUseFenceCounter(GetCurrentFenceCounter());
|
||||||
|
@ -3673,7 +3756,7 @@ void VulkanDevice::UnbindTexture(VulkanTexture* tex)
|
||||||
{
|
{
|
||||||
if (m_current_textures[i] == tex)
|
if (m_current_textures[i] == tex)
|
||||||
{
|
{
|
||||||
m_current_textures[i] = m_null_texture.get();
|
m_current_textures[i] = nullptr;
|
||||||
m_dirty_flags |= DIRTY_FLAG_TEXTURES_OR_SAMPLERS;
|
m_dirty_flags |= DIRTY_FLAG_TEXTURES_OR_SAMPLERS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3754,7 +3837,7 @@ void VulkanDevice::PreDrawCheck()
|
||||||
BeginRenderPass();
|
BeginRenderPass();
|
||||||
|
|
||||||
DebugAssert(!(m_dirty_flags & DIRTY_FLAG_INITIAL));
|
DebugAssert(!(m_dirty_flags & DIRTY_FLAG_INITIAL));
|
||||||
const u32 update_mask = (m_current_feedback_loop ? ~0u : ~DIRTY_FLAG_INPUT_ATTACHMENT);
|
const u32 update_mask = (m_current_render_pass_flags ? ~0u : ~DIRTY_FLAG_INPUT_ATTACHMENT);
|
||||||
const u32 dirty = m_dirty_flags & update_mask;
|
const u32 dirty = m_dirty_flags & update_mask;
|
||||||
m_dirty_flags = m_dirty_flags & ~update_mask;
|
m_dirty_flags = m_dirty_flags & ~update_mask;
|
||||||
|
|
||||||
|
@ -3774,6 +3857,7 @@ bool VulkanDevice::UpdateDescriptorSetsForLayout(u32 dirty)
|
||||||
{
|
{
|
||||||
[[maybe_unused]] bool new_dynamic_offsets = false;
|
[[maybe_unused]] bool new_dynamic_offsets = false;
|
||||||
|
|
||||||
|
VkPipelineLayout const vk_pipeline_layout = GetCurrentVkPipelineLayout();
|
||||||
std::array<VkDescriptorSet, 3> ds;
|
std::array<VkDescriptorSet, 3> ds;
|
||||||
u32 first_ds = 0;
|
u32 first_ds = 0;
|
||||||
u32 num_ds = 0;
|
u32 num_ds = 0;
|
||||||
|
@ -3796,8 +3880,9 @@ bool VulkanDevice::UpdateDescriptorSetsForLayout(u32 dirty)
|
||||||
if constexpr (layout == GPUPipeline::Layout::SingleTextureAndUBO ||
|
if constexpr (layout == GPUPipeline::Layout::SingleTextureAndUBO ||
|
||||||
layout == GPUPipeline::Layout::SingleTextureAndPushConstants)
|
layout == GPUPipeline::Layout::SingleTextureAndPushConstants)
|
||||||
{
|
{
|
||||||
DebugAssert(m_current_textures[0] && m_current_samplers[0] != VK_NULL_HANDLE);
|
VulkanTexture* const tex = m_current_textures[0] ? m_current_textures[0] : m_null_texture.get();
|
||||||
ds[num_ds++] = m_current_textures[0]->GetDescriptorSetWithSampler(m_current_samplers[0]);
|
DebugAssert(tex && m_current_samplers[0] != VK_NULL_HANDLE);
|
||||||
|
ds[num_ds++] = tex->GetDescriptorSetWithSampler(m_current_samplers[0]);
|
||||||
}
|
}
|
||||||
else if constexpr (layout == GPUPipeline::Layout::SingleTextureBufferAndPushConstants)
|
else if constexpr (layout == GPUPipeline::Layout::SingleTextureBufferAndPushConstants)
|
||||||
{
|
{
|
||||||
|
@ -3813,14 +3898,14 @@ bool VulkanDevice::UpdateDescriptorSetsForLayout(u32 dirty)
|
||||||
{
|
{
|
||||||
for (u32 i = 0; i < MAX_TEXTURE_SAMPLERS; i++)
|
for (u32 i = 0; i < MAX_TEXTURE_SAMPLERS; i++)
|
||||||
{
|
{
|
||||||
DebugAssert(m_current_textures[i] && m_current_samplers[i] != VK_NULL_HANDLE);
|
VulkanTexture* const tex = m_current_textures[i] ? m_current_textures[i] : m_null_texture.get();
|
||||||
dsub.AddCombinedImageSamplerDescriptorWrite(VK_NULL_HANDLE, i, m_current_textures[i]->GetView(),
|
DebugAssert(tex && m_current_samplers[i] != VK_NULL_HANDLE);
|
||||||
m_current_samplers[i], m_current_textures[i]->GetVkLayout());
|
dsub.AddCombinedImageSamplerDescriptorWrite(VK_NULL_HANDLE, i, tex->GetView(), m_current_samplers[i],
|
||||||
|
tex->GetVkLayout());
|
||||||
}
|
}
|
||||||
|
|
||||||
const u32 set = (layout == GPUPipeline::Layout::MultiTextureAndUBO) ? 1 : 0;
|
const u32 set = (layout == GPUPipeline::Layout::MultiTextureAndUBO) ? 1 : 0;
|
||||||
dsub.PushUpdate(GetCurrentCommandBuffer(), VK_PIPELINE_BIND_POINT_GRAPHICS,
|
dsub.PushUpdate(GetCurrentCommandBuffer(), VK_PIPELINE_BIND_POINT_GRAPHICS, vk_pipeline_layout, set);
|
||||||
m_pipeline_layouts[static_cast<u8>(m_current_pipeline_layout)], set);
|
|
||||||
if (num_ds == 0)
|
if (num_ds == 0)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -3834,21 +3919,42 @@ bool VulkanDevice::UpdateDescriptorSetsForLayout(u32 dirty)
|
||||||
|
|
||||||
for (u32 i = 0; i < MAX_TEXTURE_SAMPLERS; i++)
|
for (u32 i = 0; i < MAX_TEXTURE_SAMPLERS; i++)
|
||||||
{
|
{
|
||||||
DebugAssert(m_current_textures[i] && m_current_samplers[i] != VK_NULL_HANDLE);
|
VulkanTexture* const tex = m_current_textures[i] ? m_current_textures[i] : m_null_texture.get();
|
||||||
dsub.AddCombinedImageSamplerDescriptorWrite(tds, i, m_current_textures[i]->GetView(), m_current_samplers[i],
|
DebugAssert(tex && m_current_samplers[i] != VK_NULL_HANDLE);
|
||||||
m_current_textures[i]->GetVkLayout());
|
dsub.AddCombinedImageSamplerDescriptorWrite(tds, i, tex->GetView(), m_current_samplers[i], tex->GetVkLayout());
|
||||||
}
|
}
|
||||||
|
|
||||||
dsub.Update(m_device, false);
|
dsub.Update(m_device, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if constexpr (layout == GPUPipeline::Layout::SingleTextureAndUBO ||
|
if (m_num_current_render_targets > 0 &&
|
||||||
layout == GPUPipeline::Layout::SingleTextureAndPushConstants ||
|
((dirty & DIRTY_FLAG_INPUT_ATTACHMENT) ||
|
||||||
layout == GPUPipeline::Layout::SingleTextureBufferAndPushConstants)
|
(dirty & DIRTY_FLAG_PIPELINE_LAYOUT &&
|
||||||
|
(m_current_render_pass_flags & (GPUPipeline::ColorFeedbackLoop | GPUPipeline::BindRenderTargetsAsImages)))))
|
||||||
{
|
{
|
||||||
if ((dirty & DIRTY_FLAG_INPUT_ATTACHMENT) ||
|
if (m_current_render_pass_flags & GPUPipeline::BindRenderTargetsAsImages)
|
||||||
(dirty & DIRTY_FLAG_PIPELINE_LAYOUT && (m_current_feedback_loop & GPUPipeline::ColorFeedbackLoop)))
|
{
|
||||||
|
VkDescriptorSet ids = AllocateDescriptorSet(m_rov_ds_layout);
|
||||||
|
if (ids == VK_NULL_HANDLE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ds[num_ds++] = ids;
|
||||||
|
|
||||||
|
Vulkan::DescriptorSetUpdateBuilder dsub;
|
||||||
|
for (u32 i = 0; i < m_num_current_render_targets; i++)
|
||||||
|
{
|
||||||
|
dsub.AddStorageImageDescriptorWrite(ids, i, m_current_render_targets[i]->GetView(),
|
||||||
|
m_current_render_targets[i]->GetVkLayout());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Annoyingly, have to update all slots...
|
||||||
|
for (u32 i = m_num_current_render_targets; i < MAX_IMAGE_RENDER_TARGETS; i++)
|
||||||
|
dsub.AddStorageImageDescriptorWrite(ids, i, m_null_texture->GetView(), m_null_texture->GetVkLayout());
|
||||||
|
|
||||||
|
dsub.Update(m_device, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
VkDescriptorSet ids = AllocateDescriptorSet(m_feedback_loop_ds_layout);
|
VkDescriptorSet ids = AllocateDescriptorSet(m_feedback_loop_ds_layout);
|
||||||
if (ids == VK_NULL_HANDLE)
|
if (ids == VK_NULL_HANDLE)
|
||||||
|
@ -3864,9 +3970,8 @@ bool VulkanDevice::UpdateDescriptorSetsForLayout(u32 dirty)
|
||||||
}
|
}
|
||||||
|
|
||||||
DebugAssert(num_ds > 0);
|
DebugAssert(num_ds > 0);
|
||||||
vkCmdBindDescriptorSets(GetCurrentCommandBuffer(), VK_PIPELINE_BIND_POINT_GRAPHICS,
|
vkCmdBindDescriptorSets(GetCurrentCommandBuffer(), VK_PIPELINE_BIND_POINT_GRAPHICS, vk_pipeline_layout, first_ds,
|
||||||
m_pipeline_layouts[static_cast<u8>(m_current_pipeline_layout)], first_ds, num_ds, ds.data(),
|
num_ds, ds.data(), static_cast<u32>(new_dynamic_offsets),
|
||||||
static_cast<u32>(new_dynamic_offsets),
|
|
||||||
new_dynamic_offsets ? &m_uniform_buffer_position : nullptr);
|
new_dynamic_offsets ? &m_uniform_buffer_position : nullptr);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
#include "vulkan_loader.h"
|
#include "vulkan_loader.h"
|
||||||
#include "vulkan_stream_buffer.h"
|
#include "vulkan_stream_buffer.h"
|
||||||
|
|
||||||
|
#include "common/dimensional_array.h"
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
|
@ -43,6 +45,7 @@ public:
|
||||||
struct OptionalExtensions
|
struct OptionalExtensions
|
||||||
{
|
{
|
||||||
bool vk_ext_external_memory_host : 1;
|
bool vk_ext_external_memory_host : 1;
|
||||||
|
bool vk_ext_fragment_shader_interlock : 1;
|
||||||
bool vk_ext_full_screen_exclusive : 1;
|
bool vk_ext_full_screen_exclusive : 1;
|
||||||
bool vk_ext_memory_budget : 1;
|
bool vk_ext_memory_budget : 1;
|
||||||
bool vk_ext_rasterization_order_attachment_access : 1;
|
bool vk_ext_rasterization_order_attachment_access : 1;
|
||||||
|
@ -124,7 +127,7 @@ public:
|
||||||
void* MapUniformBuffer(u32 size) override;
|
void* MapUniformBuffer(u32 size) override;
|
||||||
void UnmapUniformBuffer(u32 size) override;
|
void UnmapUniformBuffer(u32 size) override;
|
||||||
void SetRenderTargets(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds,
|
void SetRenderTargets(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds,
|
||||||
GPUPipeline::RenderPassFlag feedback_loop = GPUPipeline::NoRenderPassFlags) override;
|
GPUPipeline::RenderPassFlag flags = GPUPipeline::NoRenderPassFlags) override;
|
||||||
void SetPipeline(GPUPipeline* pipeline) override;
|
void SetPipeline(GPUPipeline* pipeline) override;
|
||||||
void SetTextureSampler(u32 slot, GPUTexture* texture, GPUSampler* sampler) override;
|
void SetTextureSampler(u32 slot, GPUTexture* texture, GPUSampler* sampler) override;
|
||||||
void SetTextureBuffer(u32 slot, GPUTextureBuffer* buffer) override;
|
void SetTextureBuffer(u32 slot, GPUTextureBuffer* buffer) override;
|
||||||
|
@ -250,6 +253,14 @@ private:
|
||||||
DIRTY_FLAG_TEXTURES_OR_SAMPLERS | DIRTY_FLAG_INPUT_ATTACHMENT,
|
DIRTY_FLAG_TEXTURES_OR_SAMPLERS | DIRTY_FLAG_INPUT_ATTACHMENT,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class PipelineLayoutType : u8
|
||||||
|
{
|
||||||
|
Normal,
|
||||||
|
ColorFeedbackLoop,
|
||||||
|
BindRenderTargetsAsImages,
|
||||||
|
MaxCount,
|
||||||
|
};
|
||||||
|
|
||||||
struct RenderPassCacheKey
|
struct RenderPassCacheKey
|
||||||
{
|
{
|
||||||
struct RenderTarget
|
struct RenderTarget
|
||||||
|
@ -324,12 +335,10 @@ private:
|
||||||
using ExtensionList = std::vector<const char*>;
|
using ExtensionList = std::vector<const char*>;
|
||||||
static bool SelectInstanceExtensions(ExtensionList* extension_list, const WindowInfo& wi, OptionalExtensions* oe,
|
static bool SelectInstanceExtensions(ExtensionList* extension_list, const WindowInfo& wi, OptionalExtensions* oe,
|
||||||
bool enable_debug_utils);
|
bool enable_debug_utils);
|
||||||
bool SelectDeviceExtensions(ExtensionList* extension_list, bool enable_surface);
|
bool SelectDeviceExtensions(ExtensionList* extension_list, bool enable_surface, Error* error);
|
||||||
bool SelectDeviceFeatures();
|
bool CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer, FeatureMask disabled_features, Error* error);
|
||||||
bool CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer);
|
|
||||||
void ProcessDeviceExtensions();
|
void ProcessDeviceExtensions();
|
||||||
|
void SetFeatures(FeatureMask disabled_features, const VkPhysicalDeviceFeatures& vk_features);
|
||||||
bool CheckFeatures(FeatureMask disabled_features);
|
|
||||||
|
|
||||||
static u32 GetMaxMultisamples(VkPhysicalDevice physical_device, const VkPhysicalDeviceProperties& properties);
|
static u32 GetMaxMultisamples(VkPhysicalDevice physical_device, const VkPhysicalDeviceProperties& properties);
|
||||||
|
|
||||||
|
@ -360,6 +369,7 @@ private:
|
||||||
s32 IsRenderTargetBoundIndex(const GPUTexture* tex) const;
|
s32 IsRenderTargetBoundIndex(const GPUTexture* tex) const;
|
||||||
|
|
||||||
/// Applies any changed state.
|
/// Applies any changed state.
|
||||||
|
static PipelineLayoutType GetPipelineLayoutType(GPUPipeline::RenderPassFlag flags);
|
||||||
VkPipelineLayout GetCurrentVkPipelineLayout() const;
|
VkPipelineLayout GetCurrentVkPipelineLayout() const;
|
||||||
void SetInitialPipelineState();
|
void SetInitialPipelineState();
|
||||||
void PreDrawCheck();
|
void PreDrawCheck();
|
||||||
|
@ -437,7 +447,6 @@ private:
|
||||||
// TODO: Move to static?
|
// TODO: Move to static?
|
||||||
VkDebugUtilsMessengerEXT m_debug_messenger_callback = VK_NULL_HANDLE;
|
VkDebugUtilsMessengerEXT m_debug_messenger_callback = VK_NULL_HANDLE;
|
||||||
|
|
||||||
VkPhysicalDeviceFeatures m_device_features = {};
|
|
||||||
VkPhysicalDeviceProperties m_device_properties = {};
|
VkPhysicalDeviceProperties m_device_properties = {};
|
||||||
VkPhysicalDeviceDriverPropertiesKHR m_device_driver_properties = {};
|
VkPhysicalDeviceDriverPropertiesKHR m_device_driver_properties = {};
|
||||||
OptionalExtensions m_optional_extensions = {};
|
OptionalExtensions m_optional_extensions = {};
|
||||||
|
@ -451,7 +460,10 @@ private:
|
||||||
VkDescriptorSetLayout m_single_texture_buffer_ds_layout = VK_NULL_HANDLE;
|
VkDescriptorSetLayout m_single_texture_buffer_ds_layout = VK_NULL_HANDLE;
|
||||||
VkDescriptorSetLayout m_multi_texture_ds_layout = VK_NULL_HANDLE;
|
VkDescriptorSetLayout m_multi_texture_ds_layout = VK_NULL_HANDLE;
|
||||||
VkDescriptorSetLayout m_feedback_loop_ds_layout = VK_NULL_HANDLE;
|
VkDescriptorSetLayout m_feedback_loop_ds_layout = VK_NULL_HANDLE;
|
||||||
std::array<VkPipelineLayout, static_cast<u8>(GPUPipeline::Layout::MaxCount)> m_pipeline_layouts = {};
|
VkDescriptorSetLayout m_rov_ds_layout = VK_NULL_HANDLE;
|
||||||
|
DimensionalArray<VkPipelineLayout, static_cast<size_t>(GPUPipeline::Layout::MaxCount),
|
||||||
|
static_cast<size_t>(PipelineLayoutType::MaxCount)>
|
||||||
|
m_pipeline_layouts = {};
|
||||||
|
|
||||||
VulkanStreamBuffer m_vertex_buffer;
|
VulkanStreamBuffer m_vertex_buffer;
|
||||||
VulkanStreamBuffer m_index_buffer;
|
VulkanStreamBuffer m_index_buffer;
|
||||||
|
@ -466,8 +478,8 @@ private:
|
||||||
// Which bindings/state has to be updated before the next draw.
|
// Which bindings/state has to be updated before the next draw.
|
||||||
u32 m_dirty_flags = ALL_DIRTY_STATE;
|
u32 m_dirty_flags = ALL_DIRTY_STATE;
|
||||||
|
|
||||||
u8 m_num_current_render_targets = 0;
|
u32 m_num_current_render_targets = 0;
|
||||||
GPUPipeline::RenderPassFlag m_current_feedback_loop = GPUPipeline::NoRenderPassFlags;
|
GPUPipeline::RenderPassFlag m_current_render_pass_flags = GPUPipeline::NoRenderPassFlags;
|
||||||
std::array<VulkanTexture*, MAX_RENDER_TARGETS> m_current_render_targets = {};
|
std::array<VulkanTexture*, MAX_RENDER_TARGETS> m_current_render_targets = {};
|
||||||
VulkanTexture* m_current_depth_target = nullptr;
|
VulkanTexture* m_current_depth_target = nullptr;
|
||||||
VkFramebuffer m_current_framebuffer = VK_NULL_HANDLE;
|
VkFramebuffer m_current_framebuffer = VK_NULL_HANDLE;
|
||||||
|
@ -479,6 +491,6 @@ private:
|
||||||
std::array<VulkanTexture*, MAX_TEXTURE_SAMPLERS> m_current_textures = {};
|
std::array<VulkanTexture*, MAX_TEXTURE_SAMPLERS> m_current_textures = {};
|
||||||
std::array<VkSampler, MAX_TEXTURE_SAMPLERS> m_current_samplers = {};
|
std::array<VkSampler, MAX_TEXTURE_SAMPLERS> m_current_samplers = {};
|
||||||
VulkanTextureBuffer* m_current_texture_buffer = nullptr;
|
VulkanTextureBuffer* m_current_texture_buffer = nullptr;
|
||||||
GSVector4i m_current_viewport = {};
|
GSVector4i m_current_viewport = GSVector4i::cxpr(0, 0, 1, 1);
|
||||||
GSVector4i m_current_scissor = GSVector4i::cxpr(0, 0, 1, 1);
|
GSVector4i m_current_scissor = GSVector4i::cxpr(0, 0, 1, 1);
|
||||||
};
|
};
|
||||||
|
|
|
@ -207,7 +207,8 @@ std::unique_ptr<GPUPipeline> VulkanDevice::CreatePipeline(const GPUPipeline::Gra
|
||||||
gpb.AddDynamicState(VK_DYNAMIC_STATE_VIEWPORT);
|
gpb.AddDynamicState(VK_DYNAMIC_STATE_VIEWPORT);
|
||||||
gpb.AddDynamicState(VK_DYNAMIC_STATE_SCISSOR);
|
gpb.AddDynamicState(VK_DYNAMIC_STATE_SCISSOR);
|
||||||
|
|
||||||
gpb.SetPipelineLayout(m_pipeline_layouts[static_cast<u8>(config.layout)]);
|
gpb.SetPipelineLayout(m_pipeline_layouts[static_cast<size_t>(GetPipelineLayoutType(config.render_pass_flags))]
|
||||||
|
[static_cast<size_t>(config.layout)]);
|
||||||
|
|
||||||
if (m_optional_extensions.vk_khr_dynamic_rendering && (m_optional_extensions.vk_khr_dynamic_rendering_local_read ||
|
if (m_optional_extensions.vk_khr_dynamic_rendering && (m_optional_extensions.vk_khr_dynamic_rendering_local_read ||
|
||||||
!(config.render_pass_flags & GPUPipeline::ColorFeedbackLoop)))
|
!(config.render_pass_flags & GPUPipeline::ColorFeedbackLoop)))
|
||||||
|
|
|
@ -124,7 +124,8 @@ std::unique_ptr<VulkanTexture> VulkanTexture::Create(u32 width, u32 height, u32
|
||||||
{
|
{
|
||||||
DebugAssert(levels == 1);
|
DebugAssert(levels == 1);
|
||||||
ici.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_STORAGE_BIT |
|
ici.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_STORAGE_BIT |
|
||||||
VK_IMAGE_USAGE_SAMPLED_BIT;
|
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT |
|
||||||
|
VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue