Skip to content

Commit

Permalink
GPUDevice: Add support for Raster Ordered Views
Browse files Browse the repository at this point in the history
  • Loading branch information
stenzek committed Jul 23, 2024
1 parent e743c5d commit 1006fa0
Show file tree
Hide file tree
Showing 17 changed files with 679 additions and 360 deletions.
109 changes: 76 additions & 33 deletions src/util/d3d11_device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
m_max_feature_level = D3DCommon::GetDeviceMaxFeatureLevel(dxgi_adapter.Get());

static constexpr std::array<D3D_FEATURE_LEVEL, 3> requested_feature_levels = {
{D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0}};
static constexpr std::array<D3D_FEATURE_LEVEL, 4> requested_feature_levels = {
{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<ID3D11DeviceContext> temp_context;
Expand Down Expand Up @@ -194,6 +194,14 @@ void D3D11Device::SetFeatures(FeatureMask disabled_features)
m_features.shader_cache = true;
m_features.pipeline_cache = 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
Expand Down Expand Up @@ -567,36 +575,42 @@ void D3D11Device::ResolveTextureRegion(GPUTexture* dst, u32 dst_x, u32 dst_y, u3
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)
return true;
for (u32 i = 0; i < m_num_current_render_targets; i++)
{
if (m_current_render_targets[i] == tex)
return true;
}
}

return false;
}

void D3D11Device::ClearRenderTarget(GPUTexture* t, u32 c)
{
GPUDevice::ClearRenderTarget(t, c);
if (IsRenderTargetBound(t))
static_cast<D3D11Texture*>(t)->CommitClear(m_context.Get());
D3D11Texture* const T = static_cast<D3D11Texture*>(t);
GPUDevice::ClearRenderTarget(T, c);
if (IsRenderTargetBound(T))
T->CommitClear(m_context.Get());
}

void D3D11Device::ClearDepth(GPUTexture* t, float d)
{
GPUDevice::ClearDepth(t, d);
if (m_current_depth_target == t)
static_cast<D3D11Texture*>(t)->CommitClear(m_context.Get());
D3D11Texture* const T = static_cast<D3D11Texture*>(t);
GPUDevice::ClearDepth(T, d);
if (T == m_current_depth_target)
T->CommitClear(m_context.Get());
}

void D3D11Device::InvalidateRenderTarget(GPUTexture* t)
{
GPUDevice::InvalidateRenderTarget(t);
if (t->IsRenderTarget() ? IsRenderTargetBound(t) : (m_current_depth_target == t))
static_cast<D3D11Texture*>(t)->CommitClear(m_context.Get());
D3D11Texture* const T = static_cast<D3D11Texture*>(t);
GPUDevice::InvalidateRenderTarget(T);
if (T->IsDepthStencil() ? (m_current_depth_target == T) : IsRenderTargetBound(T))
T->CommitClear(m_context.Get());
}

void D3D11Device::SetVSyncMode(GPUVSyncMode mode, bool allow_present_throttle)
Expand Down Expand Up @@ -662,6 +676,7 @@ bool D3D11Device::BeginPresent(bool skip_present)
m_context->OMSetRenderTargets(1, m_swap_chain_rtv.GetAddressOf(), nullptr);
s_stats.num_render_passes++;
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));
m_current_depth_target = nullptr;
return true;
Expand Down Expand Up @@ -934,15 +949,20 @@ void D3D11Device::UnmapUniformBuffer(u32 size)
}

void D3D11Device::SetRenderTargets(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds,
GPUPipeline::RenderPassFlag feedback_loop)
GPUPipeline::RenderPassFlag flags)
{
ID3D11RenderTargetView* rtvs[MAX_RENDER_TARGETS];
DebugAssert(!feedback_loop);

bool changed = (m_num_current_render_targets != num_rts || m_current_depth_target != ds);
m_current_depth_target = static_cast<D3D11Texture*>(ds);

// Make sure textures aren't bound.
DebugAssert(
!(flags & (GPUPipeline::RenderPassFlag::ColorFeedbackLoop | GPUPipeline::RenderPassFlag::SampleDepthBuffer)));

// Make sure DSV isn't bound.
D3D11Texture* DS = static_cast<D3D11Texture*>(ds);
if (DS)
DS->CommitClear(m_context.Get());

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)
{
const ID3D11ShaderResourceView* srv = static_cast<D3D11Texture*>(ds)->GetD3DSRV();
Expand All @@ -958,13 +978,12 @@ void D3D11Device::SetRenderTargets(GPUTexture* const* rts, u32 num_rts, GPUTextu

for (u32 i = 0; i < num_rts; i++)
{
D3D11Texture* const dt = static_cast<D3D11Texture*>(rts[i]);
changed |= m_current_render_targets[i] != dt;
m_current_render_targets[i] = dt;
rtvs[i] = dt->GetD3DRTV();
dt->CommitClear(m_context.Get());
D3D11Texture* const RT = static_cast<D3D11Texture*>(rts[i]);
changed |= m_current_render_targets[i] != RT;
m_current_render_targets[i] = RT;
RT->CommitClear(m_context.Get());

const ID3D11ShaderResourceView* srv = dt->GetD3DSRV();
const ID3D11ShaderResourceView* srv = RT->GetD3DSRV();
for (u32 j = 0; j < MAX_TEXTURE_SAMPLERS; j++)
{
if (m_current_textures[j] && m_current_textures[j] == srv)
Expand All @@ -981,7 +1000,27 @@ void D3D11Device::SetRenderTargets(GPUTexture* const* rts, u32 num_rts, GPUTextu
return;

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)
Expand All @@ -1000,7 +1039,11 @@ void D3D11Device::SetTextureSampler(u32 slot, GPUTexture* texture, GPUSampler* s
ID3D11SamplerState* S = sampler ? static_cast<D3D11Sampler*>(sampler)->GetSamplerState() : nullptr;

// 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)
{
Expand Down Expand Up @@ -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++)
{
Expand All @@ -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");
SetRenderTargets(nullptr, 0, nullptr);
Expand Down
5 changes: 3 additions & 2 deletions src/util/d3d11_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ class D3D11Device final : public GPUDevice
void* MapUniformBuffer(u32 size) override;
void UnmapUniformBuffer(u32 size) override;
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 SetTextureSampler(u32 slot, GPUTexture* texture, GPUSampler* sampler) override;
void SetTextureBuffer(u32 slot, GPUTextureBuffer* buffer) override;
Expand Down Expand Up @@ -142,7 +142,7 @@ class D3D11Device final : public GPUDevice
bool CreateBuffers();
void DestroyBuffers();

bool IsRenderTargetBound(const GPUTexture* tex) const;
bool IsRenderTargetBound(const D3D11Texture* tex) const;

ComPtr<ID3D11RasterizerState> GetRasterizationState(const GPUPipeline::RasterizationState& rs, Error* error);
ComPtr<ID3D11DepthStencilState> GetDepthState(const GPUPipeline::DepthState& ds, Error* error);
Expand Down Expand Up @@ -180,6 +180,7 @@ class D3D11Device final : public GPUDevice
D3D11Pipeline* m_current_pipeline = nullptr;
std::array<D3D11Texture*, MAX_RENDER_TARGETS> m_current_render_targets = {};
u32 m_num_current_render_targets = 0;
GPUPipeline::RenderPassFlag m_current_render_pass_flags = GPUPipeline::NoRenderPassFlags;
D3D11Texture* m_current_depth_target = nullptr;

ID3D11InputLayout* m_current_input_layout = nullptr;
Expand Down
26 changes: 19 additions & 7 deletions src/util/d3d11_texture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
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),
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()
{
D3D11Device::GetInstance().UnbindTexture(this);
m_rtv_dsv.Reset();
m_srv.Reset();
m_texture.Reset();
}

D3D11_TEXTURE2D_DESC D3D11Texture::GetDesc() const
Expand Down Expand Up @@ -247,7 +244,7 @@ std::unique_ptr<D3D11Texture> D3D11Texture::Create(ID3D11Device* device, u32 wid
cpu_access = D3D11_CPU_ACCESS_WRITE;
break;
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;
default:
break;
Expand Down Expand Up @@ -327,8 +324,23 @@ std::unique_ptr<D3D11Texture> D3D11Texture::Create(ID3D11Device* device, u32 wid
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,
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)
Expand Down
6 changes: 5 additions & 1 deletion src/util/d3d11_texture.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ class D3D11Texture final : public GPUTexture
{
return reinterpret_cast<ID3D11RenderTargetView* const*>(m_rtv_dsv.GetAddressOf());
}
ALWAYS_INLINE ID3D11UnorderedAccessView* GetD3DUAV() const { return m_uav.Get(); }
DXGI_FORMAT GetDXGIFormat() const;

ALWAYS_INLINE operator ID3D11Texture2D*() const { return m_texture.Get(); }
Expand All @@ -72,6 +73,7 @@ class D3D11Texture final : public GPUTexture
{
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); }

static std::unique_ptr<D3D11Texture> Create(ID3D11Device* device, u32 width, u32 height, u32 layers, u32 levels,
Expand All @@ -89,11 +91,13 @@ class D3D11Texture final : public GPUTexture

private:
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<ID3D11ShaderResourceView> m_srv;
ComPtr<ID3D11View> m_rtv_dsv;
ComPtr<ID3D11UnorderedAccessView> m_uav;
u32 m_mapped_subresource = 0;
};

Expand Down
Loading

0 comments on commit 1006fa0

Please sign in to comment.