Skip to content
Open
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
10 changes: 7 additions & 3 deletions shared/sdk/Renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -753,6 +753,10 @@ void RenderContext::clear_rtv(sdk::renderer::RenderTargetView* rtv, float color[
- 0xD InterleaveNormalDepthHalfWithoutGBuffer
*/
void RenderContext::copy_texture(Texture* dest, Texture* src, Fence& fence) {
copy_texture(dest, src, &fence);
}

void RenderContext::copy_texture(Texture* dest, Texture* src, Fence* fence) {
// Okay it was actually this simple in older games but it isn't anymore in DD2+
// There's some extra garbage going on that I don't want to deal with right now
// so will just call the function directly
Expand Down Expand Up @@ -787,7 +791,7 @@ void RenderContext::copy_texture(Texture* dest, Texture* src, Fence& fence) {
// so in universal builds we dispatch at runtime but both branches must compile.
#if defined(REFRAMEWORK_UNIVERSAL) || TDB_VER < 82
auto copy_legacy = [&]() {
using CopyTexFn = void (*)(RenderContext*, Texture*, Texture*, Fence&);
using CopyTexFn = void (*)(RenderContext*, Texture*, Texture*, Fence*);
static auto func = []() -> CopyTexFn {
spdlog::info("Searching for RenderContext::copy_texture");

Expand Down Expand Up @@ -855,7 +859,7 @@ void RenderContext::copy_texture(Texture* dest, Texture* src, Fence& fence) {

#if defined(REFRAMEWORK_UNIVERSAL) || TDB_VER >= 82
auto copy_modern = [&]() {
using CopyTexFn = void (*)(RenderContext*, Texture*, int32_t, Texture*, int32_t, Fence&);
using CopyTexFn = void (*)(RenderContext*, Texture*, int32_t, Texture*, int32_t, Fence*);
static auto func = []() -> CopyTexFn {
spdlog::info("Searching for RenderContext::copy_texture (>= TDB82)");

Expand Down Expand Up @@ -2016,4 +2020,4 @@ ID3D12Resource* layer::Scene::get_depth_stencil_d3d12() {
return internal_resource->get_native_resource();
}
}
}
}
10 changes: 5 additions & 5 deletions shared/sdk/Renderer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -573,16 +573,16 @@ static_assert(sizeof(command::Fence) == 0x30);
struct CopyBase : public Base {
sdk::renderer::RenderResource* src{};
sdk::renderer::RenderResource* dst{};
::sdk::renderer::Fence fence{};
::sdk::renderer::Fence* fence{};
};

struct CopyTexture : public CopyBase {
int32_t src_subresource{-1};
int32_t dst_subresource{-1};
};

static_assert(sizeof(CopyBase) == 0x30);
static_assert(sizeof(CopyTexture) == 0x38);
static_assert(sizeof(CopyBase) == 0x28);
static_assert(sizeof(CopyTexture) == 0x30);
}

class RenderContext {
Expand All @@ -603,9 +603,9 @@ class RenderContext {
}

void copy_texture(Texture* dest, Texture* src, Fence& fence);
void copy_texture(Texture* dest, Texture* src, Fence* fence);
void copy_texture(Texture* dest, Texture* src) {
Fence fence{};
copy_texture(dest, src, fence);
copy_texture(dest, src, (Fence*)nullptr);
}

public:
Expand Down
120 changes: 93 additions & 27 deletions src/mods/vr/D3D12Component.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@ vr::EVRCompositorError D3D12Component::on_frame(VR* vr) {
runtime->fix_frame();
}

if (runtime->is_openvr()) {
m_openvr.prune_retired_textures();
}

const auto frame_count = vr->m_render_frame_count;
const auto is_multipass = vr->is_using_multipass();

Expand All @@ -94,6 +98,45 @@ vr::EVRCompositorError D3D12Component::on_frame(VR* vr) {
}
}

if (is_multipass && TemporalUpscaler::get()->ready() &&
vr->m_multipass.eye_textures[0].Get() != nullptr && vr->m_multipass.eye_textures[1].Get() != nullptr)
{
auto& ctx0 = vr->m_multipass.eye_contexts[0];
auto& ctx1 = vr->m_multipass.eye_contexts[1];

if (ctx0.texture.Get() != vr->m_multipass.eye_textures[0].Get()) {
ctx0.reset();
const auto desc = vr->m_multipass.eye_textures[0]->GetDesc();
ctx0.setup(device, vr->m_multipass.eye_textures[0].Get(), desc.Format, desc.Format);
}

if (ctx1.texture.Get() != vr->m_multipass.eye_textures[1].Get()) {
ctx1.reset();
const auto desc = vr->m_multipass.eye_textures[1]->GetDesc();
ctx1.setup(device, vr->m_multipass.eye_textures[1].Get(), desc.Format, desc.Format);
}
}

auto render_or_copy_to_texture = [&](d3d12::CommandContext& ctx, const d3d12::TextureContext& src, d3d12::TextureContext& dst, D3D12_RESOURCE_STATES src_state, D3D12_RESOURCE_STATES dst_state) {
const auto src_desc = src.texture->GetDesc();
const auto dst_desc = dst.texture->GetDesc();
const auto can_copy =
src_desc.Width == dst_desc.Width &&
src_desc.Height == dst_desc.Height &&
src_desc.DepthOrArraySize == dst_desc.DepthOrArraySize &&
src_desc.MipLevels == dst_desc.MipLevels &&
src_desc.Format == dst_desc.Format;

if (can_copy) {
ctx.copy(src.texture.Get(), dst.texture.Get(), src_state, dst_state);
return;
}

const float clear_color[4]{0.0f, 0.0f, 0.0f, 0.0f};
ctx.clear_rtv(dst, clear_color, dst_state);
render_srv_to_rtv(ctx.cmd_list.Get(), src, dst, src_state, dst_state);
};

// If m_frame_count is even, we're rendering the left eye.
if (frame_count % 2 == vr->m_left_eye_interval && !is_multipass) {
// OpenXR texture
Expand Down Expand Up @@ -151,34 +194,25 @@ vr::EVRCompositorError D3D12Component::on_frame(VR* vr) {
ctx1.setup(device, vr->m_multipass.eye_textures[1].Get(), desc.Format, desc.Format);
}

if (m_backbuffer_is_8bit) {
if (!TemporalUpscaler::get()->ready()) {
auto copy0fn = [&](d3d12::CommandContext& ctx, d3d12::TextureContext& dst, D3D12_RESOURCE_STATES src_state, D3D12_RESOURCE_STATES dst_state) {
render_or_copy_to_texture(ctx, ctx0, dst, src_state, dst_state);
};

auto copy1fn = [&](d3d12::CommandContext& ctx, d3d12::TextureContext& dst, D3D12_RESOURCE_STATES src_state, D3D12_RESOURCE_STATES dst_state) {
render_or_copy_to_texture(ctx, ctx1, dst, src_state, dst_state);
};

if (!TemporalUpscaler::get()->ready()) {
if (m_backbuffer_is_8bit) {
m_openxr.copy(0, vr->m_multipass.eye_textures[0].Get(), nullptr, D3D12_RESOURCE_STATE_COPY_DEST);
m_openxr.copy(1, vr->m_multipass.eye_textures[1].Get(), nullptr, D3D12_RESOURCE_STATE_COPY_DEST);
} else {
m_openxr.copy(0, vr->m_multipass.eye_textures[0].Get(), nullptr, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
m_openxr.copy(1, vr->m_multipass.eye_textures[1].Get(), nullptr, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
}
} else {
auto copy0fn = [&](d3d12::CommandContext& ctx, d3d12::TextureContext& dst, D3D12_RESOURCE_STATES src_state, D3D12_RESOURCE_STATES dst_state) {
const float clear_color[4]{0.0f, 0.0f, 0.0f, 0.0f};
ctx.clear_rtv(dst, clear_color, dst_state);
render_srv_to_rtv(ctx.cmd_list.Get(), vr->m_multipass.eye_contexts[0], dst, src_state, dst_state);
};

auto copy1fn = [&](d3d12::CommandContext& ctx, d3d12::TextureContext& dst, D3D12_RESOURCE_STATES src_state, D3D12_RESOURCE_STATES dst_state) {
const float clear_color[4]{0.0f, 0.0f, 0.0f, 0.0f};
ctx.clear_rtv(dst, clear_color, dst_state);
render_srv_to_rtv(ctx.cmd_list.Get(), vr->m_multipass.eye_contexts[1], dst, src_state, dst_state);
};

if (!TemporalUpscaler::get()->ready()) {
m_openxr.copy(0, ctx0.texture.Get(), nullptr, D3D12_RESOURCE_STATE_COPY_DEST, copy0fn);
m_openxr.copy(1, ctx1.texture.Get(), nullptr, D3D12_RESOURCE_STATE_COPY_DEST, copy1fn);
} else {
m_openxr.copy(0, ctx0.texture.Get(), nullptr, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, copy0fn);
m_openxr.copy(1, ctx1.texture.Get(), nullptr, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, copy1fn);
}
} else {
m_openxr.copy(0, ctx0.texture.Get(), nullptr, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, copy0fn);
m_openxr.copy(1, ctx1.texture.Get(), nullptr, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, copy1fn);
}
} else {
// just copy the backbuffer to both eyes as a fallback
Expand All @@ -202,8 +236,14 @@ vr::EVRCompositorError D3D12Component::on_frame(VR* vr) {
m_openvr.copy_left(vr->m_multipass.eye_textures[0].Get(), D3D12_RESOURCE_STATE_COPY_DEST);
m_openvr.copy_right(vr->m_multipass.eye_textures[1].Get(), D3D12_RESOURCE_STATE_COPY_DEST);
} else {
m_openvr.copy_left(vr->m_multipass.eye_textures[0].Get(), D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
m_openvr.copy_right(vr->m_multipass.eye_textures[1].Get(), D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
auto& left = m_openvr.acquire_left();
auto& right = m_openvr.acquire_right();

render_or_copy_to_texture(left.commands, vr->m_multipass.eye_contexts[0], left, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
render_or_copy_to_texture(right.commands, vr->m_multipass.eye_contexts[1], right, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);

left.commands.execute();
right.commands.execute();
}
} else {
// just copy the backbuffer to both eyes as a fallback
Expand Down Expand Up @@ -252,6 +292,7 @@ vr::EVRCompositorError D3D12Component::on_frame(VR* vr) {
}

++m_openvr.texture_counter;
++m_openvr.submission_serial;
}
}

Expand Down Expand Up @@ -304,7 +345,28 @@ vr::EVRCompositorError D3D12Component::on_frame(VR* vr) {

// Allows the desktop window to be recorded.
if (vr->m_desktop_fix->value()) {
if (runtime->ready() && m_prev_backbuffer != backbuffer && m_prev_backbuffer != nullptr) {
bool mirrored_current_frame = false;

if (is_multipass && TemporalUpscaler::get()->ready() && vr->m_multipass.eye_textures[0].Get() != nullptr) {
const auto src_desc = vr->m_multipass.eye_textures[0]->GetDesc();
const auto dst_desc = backbuffer->GetDesc();
const auto can_copy =
src_desc.Width == dst_desc.Width &&
src_desc.Height == dst_desc.Height &&
src_desc.DepthOrArraySize == dst_desc.DepthOrArraySize &&
src_desc.MipLevels == dst_desc.MipLevels &&
src_desc.Format == dst_desc.Format;

if (can_copy) {
auto& copier = m_generic_copiers[frame_count % m_generic_copiers.size()];
copier.wait(INFINITE);
copier.copy(vr->m_multipass.eye_textures[0].Get(), backbuffer.Get(), D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_PRESENT);
copier.execute();
mirrored_current_frame = true;
}
}

if (!mirrored_current_frame && runtime->ready() && m_prev_backbuffer != backbuffer && m_prev_backbuffer != nullptr) {
auto& copier = m_generic_copiers[frame_count % m_generic_copiers.size()];
copier.wait(INFINITE);
copier.copy(m_prev_backbuffer.Get(), backbuffer.Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_PRESENT);
Expand All @@ -326,6 +388,10 @@ void D3D12Component::on_reset(VR* vr) {

auto runtime = vr->get_runtime();

if (runtime->is_openvr()) {
m_openvr.retire_textures();
}

for (auto& ctx : m_openvr.left_eye_tex) {
ctx.reset();
}
Expand Down Expand Up @@ -541,8 +607,8 @@ void D3D12Component::setup() {

setup_sprite_batch_pso(rt_desc.Format);

m_backbuffer_size[0] = real_backbuffer_desc.Width;
m_backbuffer_size[1] = real_backbuffer_desc.Height;
m_backbuffer_size[0] = backbuffer_desc.Width;
m_backbuffer_size[1] = backbuffer_desc.Height;

spdlog::info("[VR] d3d12 textures have been setup");
m_force_reset = false;
Expand Down
42 changes: 42 additions & 0 deletions src/mods/vr/D3D12Component.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#pragma once

#include <array>
#include <deque>
#include <optional>
#include <vector>

#include <d3d11.h>
#include <d3d12.h>
Expand Down Expand Up @@ -62,6 +64,11 @@ class D3D12Component {

// Mimicking what OpenXR does.
struct OpenVR {
struct RetiredTextureSet {
uint64_t release_after_submission{};
std::vector<ComPtr<ID3D12Resource>> textures{};
};

d3d12::TextureContext& get_left() {
auto& ctx = this->left_eye_tex[this->texture_counter % left_eye_tex.size()];

Expand Down Expand Up @@ -100,9 +107,44 @@ class D3D12Component {
ctx.commands.execute();
}

void retire_textures() {
RetiredTextureSet retired{};
retired.release_after_submission = this->submission_serial + 6;

for (auto& ctx : this->left_eye_tex) {
if (ctx.texture != nullptr) {
retired.textures.emplace_back(ctx.texture);
}
}

for (auto& ctx : this->right_eye_tex) {
if (ctx.texture != nullptr) {
retired.textures.emplace_back(ctx.texture);
}
}

if (retired.textures.empty()) {
return;
}

this->retired_textures.emplace_back(std::move(retired));

while (this->retired_textures.size() > 2) {
this->retired_textures.pop_front();
}
}

void prune_retired_textures() {
while (!this->retired_textures.empty() && this->submission_serial >= this->retired_textures.front().release_after_submission) {
this->retired_textures.pop_front();
}
}

std::array<d3d12::TextureContext, 3> left_eye_tex{};
std::array<d3d12::TextureContext, 3> right_eye_tex{};
std::deque<RetiredTextureSet> retired_textures{};
uint32_t texture_counter{0};
uint64_t submission_serial{};
DXGI_FORMAT last_format{};
} m_openvr;

Expand Down
48 changes: 39 additions & 9 deletions src/mods/vr/d3d12/DirectXTK.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,29 @@ void render_srv_to_rtv(
scissor_rect.right = (LONG)dst_desc.Width;
scissor_rect.bottom = (LONG)dst_desc.Height;

// Transition dst to D3D12_RESOURCE_STATE_RENDER_TARGET
D3D12_RESOURCE_BARRIER barrier{};
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
barrier.Transition.pResource = dst.texture.Get();
D3D12_RESOURCE_BARRIER barriers[2]{};
uint32_t barrier_count = 0;

if (dst_state != D3D12_RESOURCE_STATE_RENDER_TARGET) {
if (src_state != D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE) {
auto& barrier = barriers[barrier_count++];
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
barrier.Transition.pResource = src.texture.Get();
barrier.Transition.StateBefore = src_state;
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
}

if (dst_state != D3D12_RESOURCE_STATE_RENDER_TARGET) {
auto& barrier = barriers[barrier_count++];
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
barrier.Transition.pResource = dst.texture.Get();
barrier.Transition.StateBefore = dst_state;
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
command_list->ResourceBarrier(1, &barrier);
}

if (barrier_count > 0) {
command_list->ResourceBarrier(barrier_count, barriers);
}

// Set RTV to backbuffer
Expand All @@ -61,11 +74,28 @@ void render_srv_to_rtv(

batch->End();

// Transition dst to dst_state
barrier_count = 0;

if (dst_state != D3D12_RESOURCE_STATE_RENDER_TARGET) {
auto& barrier = barriers[barrier_count++];
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
barrier.Transition.pResource = dst.texture.Get();
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
barrier.Transition.StateAfter = dst_state;
command_list->ResourceBarrier(1, &barrier);
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
}

if (src_state != D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE) {
auto& barrier = barriers[barrier_count++];
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
barrier.Transition.pResource = src.texture.Get();
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
barrier.Transition.StateAfter = src_state;
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
}

if (barrier_count > 0) {
command_list->ResourceBarrier(barrier_count, barriers);
}
}
}
}