Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .claude/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,13 @@ Follow conventional commit format for consistency:
- **Single Responsibility**: Each feature class should handle one graphics technique only
- **Function Complexity**: Keep rendering functions focused; extract complex GPU operations into separate methods
- **Resource Management**: Always pair graphics resource creation with proper cleanup (RAII)
- **D3D11 Resource Naming**: Every D3D11 resource must be named for RenderDoc debuggability. Use
`Util::SetResourceName(ptr, "Feature::ResourceDescription")` after raw `device->Create*` calls.
For wrapper types (`Texture2D`, `Buffer`, `ConstantBuffer`, etc. in `Buffer.h`), pass the name
to the constructor and views are named automatically. Convention: `"Feature::Name"` for the
resource, `"Feature::Name SRV"` / `"Feature::Name UAV"` etc. for views (handled automatically
by the wrappers). The canonical implementation lives in `Util::SetResourceName` (`Utils/D3D.cpp`);
never duplicate the GUID or re-implement the call inline.

### Common Pitfalls to Avoid

Expand All @@ -509,3 +516,4 @@ Follow conventional commit format for consistency:
- **Buffer Conflicts**: Check hlslkit buffer scanning to avoid GPU register conflicts that cause rendering issues
- **Graphics State Corruption**: Minimize DirectX state changes; restore state after modifications
- **Thread Safety**: Graphics operations must consider Skyrim's rendering thread vs game logic thread
- **DRY Violations in Cross-Cutting Refactors**: When adding a utility pattern across many files (e.g., resource naming, debug hooks), check whether the implementation exists in multiple places before writing a new one. For example, `Buffer.h` helper classes and raw `device->Create*` callsites both need `SetResourceName` — ensure they share a single implementation, not duplicate GUID definitions or parallel helper functions. Use a forward declaration in headers to delegate to the canonical implementation in `Utils/D3D.cpp` rather than re-implementing inline.
87 changes: 80 additions & 7 deletions src/Buffer.h
Original file line number Diff line number Diff line change
@@ -1,13 +1,33 @@
#pragma once

#include <d3d11.h>
#include <string>

#include <Windows.Foundation.h>
#include <stdio.h>
#include <winrt/base.h>
#include <wrl\client.h>
#include <wrl\wrappers\corewrappers.h>

// Forward declaration — keeps Buffer.h free of Utils/D3D.h's game-type dependencies
namespace Util
{
void SetResourceName(ID3D11DeviceChild* Resource, const char* Format, ...);
}

namespace detail
{
inline void SetD3DName(ID3D11DeviceChild* resource, const std::string& name, const char* suffix = nullptr)
{
if (!resource || name.empty())
return;
if (suffix)
Util::SetResourceName(resource, "%s%s", name.c_str(), suffix);
else
Util::SetResourceName(resource, "%s", name.c_str());
}
}

#define STATIC_ASSERT_ALIGNAS_16(structName) \
static_assert(sizeof(structName) % 16 == 0, #structName " is not a multiple of 16.");

Expand Down Expand Up @@ -51,11 +71,13 @@ D3D11_BUFFER_DESC ConstantBufferDesc(bool dynamic = true)
class ConstantBuffer
{
public:
explicit ConstantBuffer(D3D11_BUFFER_DESC const& a_desc) :
explicit ConstantBuffer(D3D11_BUFFER_DESC const& a_desc, const char* name = nullptr) :
desc(a_desc)
{
auto device = globals::d3d::device;
DX::ThrowIfFailed(device->CreateBuffer(&desc, nullptr, resource.put()));
if (name)
detail::SetD3DName(resource.get(), name);
}

ID3D11Buffer* CB() const { return resource.get(); }
Expand Down Expand Up @@ -103,11 +125,15 @@ D3D11_BUFFER_DESC StructuredBufferDesc(UINT a_count = 1, bool cpu_access = true)
class StructuredBuffer
{
public:
StructuredBuffer(D3D11_BUFFER_DESC const& a_desc, UINT a_count) :
StructuredBuffer(D3D11_BUFFER_DESC const& a_desc, UINT a_count, const char* name = nullptr) :
desc(a_desc), count(a_count)
{
auto device = globals::d3d::device;
DX::ThrowIfFailed(device->CreateBuffer(&desc, nullptr, resource.put()));
if (name) {
name_ = name;
detail::SetD3DName(resource.get(), name_);
}
}

ID3D11ShaderResourceView* SRV(size_t i = 0) const { return srvs[i].get(); }
Expand All @@ -123,6 +149,7 @@ class StructuredBuffer
srv_desc.Buffer.NumElements = count;
winrt::com_ptr<ID3D11ShaderResourceView> srv;
DX::ThrowIfFailed(device->CreateShaderResourceView(resource.get(), &srv_desc, srv.put()));
detail::SetD3DName(srv.get(), name_, " SRV");
srvs.push_back(srv);
}

Expand All @@ -137,6 +164,7 @@ class StructuredBuffer
uav_desc.Buffer.NumElements = count;
winrt::com_ptr<ID3D11UnorderedAccessView> uav;
DX::ThrowIfFailed(device->CreateUnorderedAccessView(resource.get(), &uav_desc, uav.put()));
detail::SetD3DName(uav.get(), name_, " UAV");
uavs.push_back(uav);
}

Expand All @@ -162,109 +190,141 @@ class StructuredBuffer
winrt::com_ptr<ID3D11Buffer> resource;
D3D11_BUFFER_DESC desc;
UINT count;
std::string name_;
};

class Buffer
{
public:
explicit Buffer(D3D11_BUFFER_DESC const& a_desc, D3D11_SUBRESOURCE_DATA* a_init = nullptr) :
explicit Buffer(D3D11_BUFFER_DESC const& a_desc, D3D11_SUBRESOURCE_DATA* a_init = nullptr, const char* name = nullptr) :
desc(a_desc)
{
auto device = globals::d3d::device;
DX::ThrowIfFailed(device->CreateBuffer(&desc, a_init, resource.put()));
if (name) {
name_ = name;
detail::SetD3DName(resource.get(), name_);
}
}

void CreateSRV(D3D11_SHADER_RESOURCE_VIEW_DESC const& a_desc)
{
auto device = globals::d3d::device;
DX::ThrowIfFailed(device->CreateShaderResourceView(resource.get(), &a_desc, srv.put()));
detail::SetD3DName(srv.get(), name_, " SRV");
}

void CreateUAV(D3D11_UNORDERED_ACCESS_VIEW_DESC const& a_desc)
{
auto device = globals::d3d::device;
DX::ThrowIfFailed(device->CreateUnorderedAccessView(resource.get(), &a_desc, uav.put()));
detail::SetD3DName(uav.get(), name_, " UAV");
}

D3D11_BUFFER_DESC desc;
winrt::com_ptr<ID3D11Buffer> resource;
winrt::com_ptr<ID3D11ShaderResourceView> srv;
winrt::com_ptr<ID3D11UnorderedAccessView> uav;

private:
std::string name_;
};

class Texture1D
{
public:
explicit Texture1D(D3D11_TEXTURE1D_DESC const& a_desc) :
explicit Texture1D(D3D11_TEXTURE1D_DESC const& a_desc, const char* name = nullptr) :
desc(a_desc)
{
auto device = globals::d3d::device;
DX::ThrowIfFailed(device->CreateTexture1D(&desc, nullptr, resource.put()));
if (name) {
name_ = name;
detail::SetD3DName(resource.get(), name_);
}
}

void CreateSRV(D3D11_SHADER_RESOURCE_VIEW_DESC const& a_desc)
{
auto device = globals::d3d::device;
DX::ThrowIfFailed(device->CreateShaderResourceView(resource.get(), &a_desc, srv.put()));
detail::SetD3DName(srv.get(), name_, " SRV");
}

void CreateUAV(D3D11_UNORDERED_ACCESS_VIEW_DESC const& a_desc)
{
auto device = globals::d3d::device;
DX::ThrowIfFailed(device->CreateUnorderedAccessView(resource.get(), &a_desc, uav.put()));
detail::SetD3DName(uav.get(), name_, " UAV");
}

void CreateRTV(D3D11_RENDER_TARGET_VIEW_DESC const& a_desc)
{
auto device = globals::d3d::device;
DX::ThrowIfFailed(device->CreateRenderTargetView(resource.get(), &a_desc, rtv.put()));
detail::SetD3DName(rtv.get(), name_, " RTV");
}

D3D11_TEXTURE1D_DESC desc;
winrt::com_ptr<ID3D11Texture1D> resource;
winrt::com_ptr<ID3D11ShaderResourceView> srv;
winrt::com_ptr<ID3D11UnorderedAccessView> uav;
winrt::com_ptr<ID3D11RenderTargetView> rtv;

private:
std::string name_;
};

class Texture2D
{
public:
explicit Texture2D(D3D11_TEXTURE2D_DESC const& a_desc) :
explicit Texture2D(D3D11_TEXTURE2D_DESC const& a_desc, const char* name = nullptr) :
desc(a_desc)
{
auto device = globals::d3d::device;
DX::ThrowIfFailed(device->CreateTexture2D(&desc, nullptr, resource.put()));
if (name) {
name_ = name;
detail::SetD3DName(resource.get(), name_);
}
}

explicit Texture2D(ID3D11Texture2D* a_resource)
explicit Texture2D(ID3D11Texture2D* a_resource, const char* name = nullptr)
{
a_resource->GetDesc(&desc);
resource.attach(a_resource);
if (name) {
name_ = name;
detail::SetD3DName(resource.get(), name_);
}
}

void CreateSRV(D3D11_SHADER_RESOURCE_VIEW_DESC const& a_desc)
{
auto device = globals::d3d::device;
DX::ThrowIfFailed(device->CreateShaderResourceView(resource.get(), &a_desc, srv.put()));
detail::SetD3DName(srv.get(), name_, " SRV");
}

void CreateUAV(D3D11_UNORDERED_ACCESS_VIEW_DESC const& a_desc)
{
auto device = globals::d3d::device;
DX::ThrowIfFailed(device->CreateUnorderedAccessView(resource.get(), &a_desc, uav.put()));
detail::SetD3DName(uav.get(), name_, " UAV");
}

void CreateRTV(D3D11_RENDER_TARGET_VIEW_DESC const& a_desc)
{
auto device = globals::d3d::device;
DX::ThrowIfFailed(device->CreateRenderTargetView(resource.get(), &a_desc, rtv.put()));
detail::SetD3DName(rtv.get(), name_, " RTV");
}

void CreateDSV(D3D11_DEPTH_STENCIL_VIEW_DESC const& a_desc)
{
auto device = globals::d3d::device;
DX::ThrowIfFailed(device->CreateDepthStencilView(resource.get(), &a_desc, dsv.put()));
detail::SetD3DName(dsv.get(), name_, " DSV");
}

D3D11_TEXTURE2D_DESC desc;
Expand All @@ -273,39 +333,52 @@ class Texture2D
winrt::com_ptr<ID3D11UnorderedAccessView> uav;
winrt::com_ptr<ID3D11RenderTargetView> rtv;
winrt::com_ptr<ID3D11DepthStencilView> dsv;

private:
std::string name_;
};

class Texture3D
{
public:
explicit Texture3D(D3D11_TEXTURE3D_DESC const& a_desc) :
explicit Texture3D(D3D11_TEXTURE3D_DESC const& a_desc, const char* name = nullptr) :
desc(a_desc)
{
auto device = globals::d3d::device;
DX::ThrowIfFailed(device->CreateTexture3D(&desc, nullptr, resource.put()));
if (name) {
name_ = name;
detail::SetD3DName(resource.get(), name_);
}
}

void CreateSRV(D3D11_SHADER_RESOURCE_VIEW_DESC const& a_desc)
{
auto device = globals::d3d::device;
DX::ThrowIfFailed(device->CreateShaderResourceView(resource.get(), &a_desc, srv.put()));
detail::SetD3DName(srv.get(), name_, " SRV");
}

void CreateUAV(D3D11_UNORDERED_ACCESS_VIEW_DESC const& a_desc)
{
auto device = globals::d3d::device;
DX::ThrowIfFailed(device->CreateUnorderedAccessView(resource.get(), &a_desc, uav.put()));
detail::SetD3DName(uav.get(), name_, " UAV");
}

void CreateRTV(D3D11_RENDER_TARGET_VIEW_DESC const& a_desc)
{
auto device = globals::d3d::device;
DX::ThrowIfFailed(device->CreateRenderTargetView(resource.get(), &a_desc, rtv.put()));
detail::SetD3DName(rtv.get(), name_, " RTV");
}

D3D11_TEXTURE3D_DESC desc;
winrt::com_ptr<ID3D11Texture3D> resource;
winrt::com_ptr<ID3D11ShaderResourceView> srv;
winrt::com_ptr<ID3D11UnorderedAccessView> uav;
winrt::com_ptr<ID3D11RenderTargetView> rtv;

private:
std::string name_;
};
9 changes: 8 additions & 1 deletion src/Deferred.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "ShaderCache.h"
#include "State.h"
#include "TruePBR.h"
#include "Utils/D3D.h"

#include "Features/DynamicCubemaps.h"
#include "Features/IBL.h"
Expand Down Expand Up @@ -126,9 +127,11 @@ void Deferred::SetupResources()
samplerDesc.MinLOD = 0;
samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;
DX::ThrowIfFailed(device->CreateSamplerState(&samplerDesc, &linearSampler));
Util::SetResourceName(linearSampler, "Deferred::LinearSampler");

samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
DX::ThrowIfFailed(device->CreateSamplerState(&samplerDesc, &pointSampler));
Util::SetResourceName(pointSampler, "Deferred::PointSampler");
}

{
Expand All @@ -139,13 +142,15 @@ void Deferred::SetupResources()
blendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
blendDesc.RenderTarget[1].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_BLUE;
DX::ThrowIfFailed(device->CreateBlendState(&blendDesc, compositeBlendState.put()));
Util::SetResourceName(compositeBlendState.get(), "Deferred::CompositeBlendState");

D3D11_DEPTH_STENCIL_DESC dsDesc{};
dsDesc.DepthEnable = TRUE;
dsDesc.DepthFunc = D3D11_COMPARISON_GREATER;
dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
dsDesc.StencilEnable = FALSE;
DX::ThrowIfFailed(device->CreateDepthStencilState(&dsDesc, compositeDepthStencilState.put()));
Util::SetResourceName(compositeDepthStencilState.get(), "Deferred::CompositeDepthStencilState");

D3D11_DEPTH_STENCIL_DESC stencilDsDesc{};
stencilDsDesc.DepthEnable = TRUE;
Expand All @@ -160,12 +165,14 @@ void Deferred::SetupResources()
stencilDsDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
stencilDsDesc.BackFace = stencilDsDesc.FrontFace;
DX::ThrowIfFailed(device->CreateDepthStencilState(&stencilDsDesc, compositeStencilDSState.put()));
Util::SetResourceName(compositeStencilDSState.get(), "Deferred::CompositeStencilDSState");

D3D11_RASTERIZER_DESC rsDesc{};
rsDesc.FillMode = D3D11_FILL_SOLID;
rsDesc.CullMode = D3D11_CULL_NONE;
rsDesc.DepthClipEnable = FALSE;
DX::ThrowIfFailed(device->CreateRasterizerState(&rsDesc, compositeRasterizerState.put()));
Util::SetResourceName(compositeRasterizerState.get(), "Deferred::CompositeRasterizerState");
}

// Directional shadow structured buffer (t98): CPU-written each frame, read-only on GPU.
Expand All @@ -186,7 +193,7 @@ void Deferred::SetupResources()
srvDesc.Buffer.NumElements = 1;

delete directionalShadowLights;
directionalShadowLights = new Buffer(sbDesc);
directionalShadowLights = new Buffer(sbDesc, nullptr, "Deferred::DirectionalShadowLights");
directionalShadowLights->CreateSRV(srvDesc);
}
}
Expand Down
Loading
Loading