Compare commits

...

5 Commits

Author SHA1 Message Date
Skyth 5e2dafd7a0 Delay creation of textures. 2025-02-02 23:53:14 +03:00
Skyth (Asilkan) aaad10d797 Implement copy bypass optimization. (#262)
* Initial work on copy bypass optimization.

* Force depth stencil textures to be transient.

* Get rid of texture copying for shadow maps.

* Move barrier populate function.

* Set viewport/scissor rect explicitly for MSAA depth resolve.
2025-02-02 21:29:47 +03:00
Skyth (Asilkan) 342d696f99 Implement vertical marquee fade. (#261) 2025-02-02 20:09:19 +03:00
Hyper 0426b79094 config: update key bindings enum template 2025-02-02 15:51:16 +00:00
Hyper 3497d9b34b CTitleStateIntro_patches: fixed message inconsistencies (#259) 2025-02-01 13:37:48 +00:00
14 changed files with 643 additions and 374 deletions
+11 -10
View File
@@ -1,15 +1,16 @@
#pragma once
#define IMGUI_SHADER_MODIFIER_NONE 0
#define IMGUI_SHADER_MODIFIER_SCANLINE 1
#define IMGUI_SHADER_MODIFIER_CHECKERBOARD 2
#define IMGUI_SHADER_MODIFIER_SCANLINE_BUTTON 3
#define IMGUI_SHADER_MODIFIER_TEXT_SKEW 4
#define IMGUI_SHADER_MODIFIER_MARQUEE_FADE 5
#define IMGUI_SHADER_MODIFIER_GRAYSCALE 6
#define IMGUI_SHADER_MODIFIER_TITLE_BEVEL 7
#define IMGUI_SHADER_MODIFIER_CATEGORY_BEVEL 8
#define IMGUI_SHADER_MODIFIER_RECTANGLE_BEVEL 9
#define IMGUI_SHADER_MODIFIER_NONE 0
#define IMGUI_SHADER_MODIFIER_SCANLINE 1
#define IMGUI_SHADER_MODIFIER_CHECKERBOARD 2
#define IMGUI_SHADER_MODIFIER_SCANLINE_BUTTON 3
#define IMGUI_SHADER_MODIFIER_TEXT_SKEW 4
#define IMGUI_SHADER_MODIFIER_HORIZONTAL_MARQUEE_FADE 5
#define IMGUI_SHADER_MODIFIER_VERTICAL_MARQUEE_FADE 6
#define IMGUI_SHADER_MODIFIER_GRAYSCALE 7
#define IMGUI_SHADER_MODIFIER_TITLE_BEVEL 8
#define IMGUI_SHADER_MODIFIER_CATEGORY_BEVEL 9
#define IMGUI_SHADER_MODIFIER_RECTANGLE_BEVEL 10
#ifdef __cplusplus
+9 -1
View File
@@ -135,7 +135,7 @@ float4 main(in Interpolators interpolators) : SV_Target
}
}
if (g_PushConstants.ShaderModifier == IMGUI_SHADER_MODIFIER_MARQUEE_FADE)
if (g_PushConstants.ShaderModifier == IMGUI_SHADER_MODIFIER_HORIZONTAL_MARQUEE_FADE)
{
float minAlpha = saturate((interpolators.Position.x - g_PushConstants.BoundsMin.x) / g_PushConstants.Scale.x);
float maxAlpha = saturate((g_PushConstants.BoundsMax.x - interpolators.Position.x) / g_PushConstants.Scale.x);
@@ -143,6 +143,14 @@ float4 main(in Interpolators interpolators) : SV_Target
color.a *= minAlpha;
color.a *= maxAlpha;
}
else if (g_PushConstants.ShaderModifier == IMGUI_SHADER_MODIFIER_VERTICAL_MARQUEE_FADE)
{
float minAlpha = saturate((interpolators.Position.y - g_PushConstants.BoundsMin.y) / g_PushConstants.Scale.y);
float maxAlpha = saturate((g_PushConstants.BoundsMax.y - interpolators.Position.y) / g_PushConstants.Scale.y);
color.a *= minAlpha;
color.a *= maxAlpha;
}
else if (any(g_PushConstants.BoundsMin != g_PushConstants.BoundsMax))
{
float2 factor = saturate((interpolators.Position.xy - g_PushConstants.BoundsMin) / (g_PushConstants.BoundsMax - g_PushConstants.BoundsMin));
+2 -1
View File
@@ -7,7 +7,8 @@ void main(in float2 position : POSITION, in float2 uv : TEXCOORD, in float4 colo
if (position.y < g_PushConstants.Origin.y)
position.x += g_PushConstants.Scale.x;
}
else if (g_PushConstants.ShaderModifier != IMGUI_SHADER_MODIFIER_MARQUEE_FADE)
else if (g_PushConstants.ShaderModifier != IMGUI_SHADER_MODIFIER_HORIZONTAL_MARQUEE_FADE &&
g_PushConstants.ShaderModifier != IMGUI_SHADER_MODIFIER_VERTICAL_MARQUEE_FADE)
{
position.xy = g_PushConstants.Origin + (position.xy - g_PushConstants.Origin) * g_PushConstants.Scale;
}
+407 -175
View File
@@ -155,11 +155,11 @@ static GuestSurface* g_renderTarget;
static GuestSurface* g_depthStencil;
static RenderFramebuffer* g_framebuffer;
static RenderViewport g_viewport(0.0f, 0.0f, 1280.0f, 720.0f);
static bool g_halfPixel = true;
static PipelineState g_pipelineState;
static int32_t g_depthBias;
static float g_slopeScaledDepthBias;
static SharedConstants g_sharedConstants;
static GuestTexture* g_textures[16];
static RenderSamplerDesc g_samplerDescs[16];
static bool g_scissorTestEnable = false;
static RenderRect g_scissorRect;
@@ -563,7 +563,8 @@ static void DestructTempResources()
if (texture->mappedMemory != nullptr)
g_userHeap.Free(texture->mappedMemory);
g_textureDescriptorAllocator.free(texture->descriptorIndex);
if (texture->descriptorIndex != NULL)
g_textureDescriptorAllocator.free(texture->descriptorIndex);
if (texture->patchedTexture != nullptr)
g_textureDescriptorAllocator.free(texture->patchedTexture->descriptorIndex);
@@ -681,6 +682,9 @@ enum class CsdFilterState
static CsdFilterState g_csdFilterState;
static ankerl::unordered_dense::set<GuestSurface*> g_pendingSurfaceCopies;
static ankerl::unordered_dense::set<GuestSurface*> g_pendingMsaaResolves;
enum class RenderCommandType
{
SetRenderState,
@@ -694,6 +698,7 @@ enum class RenderCommandType
StretchRect,
SetRenderTarget,
SetDepthStencilSurface,
ExecutePendingStretchRectCommands,
Clear,
SetViewport,
SetTexture,
@@ -710,7 +715,7 @@ enum class RenderCommandType
SetVertexShader,
SetStreamSource,
SetIndices,
SetPixelShader
SetPixelShader,
};
struct RenderCommand
@@ -1465,6 +1470,8 @@ static void BeginCommandList()
g_sharedConstants.textureCubeIndices[i] = TEXTURE_DESCRIPTOR_NULL_TEXTURE_CUBE;
}
memset(g_textures, 0, sizeof(g_textures));
if (Config::GITextureFiltering == EGITextureFiltering::Bicubic)
g_pipelineState.specConstants |= SPEC_CONSTANT_BICUBIC_GI_FILTER;
else
@@ -2409,9 +2416,12 @@ static std::atomic<bool> g_executedCommandList;
void Video::Present()
{
RenderCommand cmd;
cmd.type = RenderCommandType::ExecutePendingStretchRectCommands;
g_renderQueue.enqueue(cmd);
DrawImGui();
RenderCommand cmd;
cmd.type = RenderCommandType::ExecuteCommandList;
g_renderQueue.enqueue(cmd);
@@ -2693,56 +2703,65 @@ static RenderFormat ConvertFormat(uint32_t format)
}
}
static GuestTexture* CreateTexture(uint32_t width, uint32_t height, uint32_t depth, uint32_t levels, uint32_t usage, uint32_t format, uint32_t pool, uint32_t type)
void GuestTexture::CreateTexture()
{
const auto texture = g_userHeap.AllocPhysical<GuestTexture>(type == 17 ? ResourceType::VolumeTexture : ResourceType::Texture);
RenderTextureDesc desc;
desc.dimension = texture->type == ResourceType::VolumeTexture ? RenderTextureDimension::TEXTURE_3D : RenderTextureDimension::TEXTURE_2D;
desc.dimension = type == ResourceType::VolumeTexture ? RenderTextureDimension::TEXTURE_3D : RenderTextureDimension::TEXTURE_2D;
desc.width = width;
desc.height = height;
desc.depth = depth;
desc.mipLevels = levels;
desc.arraySize = 1;
desc.format = ConvertFormat(format);
desc.format = format;
desc.flags = (desc.format == RenderFormat::D32_FLOAT) ? RenderTextureFlag::DEPTH_TARGET : RenderTextureFlag::NONE;
texture->textureHolder = g_device->createTexture(desc);
texture->texture = texture->textureHolder.get();
textureHolder = g_device->createTexture(desc);
texture = textureHolder.get();
RenderTextureViewDesc viewDesc;
viewDesc.format = desc.format;
viewDesc.dimension = texture->type == ResourceType::VolumeTexture ? RenderTextureViewDimension::TEXTURE_3D : RenderTextureViewDimension::TEXTURE_2D;
viewDesc.dimension = type == ResourceType::VolumeTexture ? RenderTextureViewDimension::TEXTURE_3D : RenderTextureViewDimension::TEXTURE_2D;
viewDesc.mipLevels = levels;
textureView = texture->createTextureView(viewDesc);
viewDimension = viewDesc.dimension;
descriptorIndex = g_textureDescriptorAllocator.allocate();
g_textureDescriptorSet->setTexture(descriptorIndex, texture, RenderTextureLayout::SHADER_READ, textureView.get());
#ifdef _DEBUG
texture->setName(fmt::format("Texture {:X}", g_memory.MapVirtual(this)));
#endif
}
static GuestTexture* CreateTexture(uint32_t width, uint32_t height, uint32_t depth, uint32_t levels, uint32_t usage, uint32_t format, uint32_t pool, uint32_t type)
{
const auto texture = g_userHeap.AllocPhysical<GuestTexture>(type == 17 ? ResourceType::VolumeTexture : ResourceType::Texture);
texture->width = width;
texture->height = height;
texture->depth = depth;
texture->levels = levels;
texture->format = ConvertFormat(format);
switch (format)
{
case D3DFMT_D24FS8:
case D3DFMT_D24S8:
case D3DFMT_L8:
case D3DFMT_L8_2:
viewDesc.componentMapping = RenderComponentMapping(RenderSwizzle::R, RenderSwizzle::R, RenderSwizzle::R, RenderSwizzle::ONE);
texture->componentMapping = RenderComponentMapping(RenderSwizzle::R, RenderSwizzle::R, RenderSwizzle::R, RenderSwizzle::ONE);
break;
case D3DFMT_X8R8G8B8:
viewDesc.componentMapping = RenderComponentMapping(RenderSwizzle::G, RenderSwizzle::B, RenderSwizzle::A, RenderSwizzle::ONE);
texture->componentMapping = RenderComponentMapping(RenderSwizzle::G, RenderSwizzle::B, RenderSwizzle::A, RenderSwizzle::ONE);
break;
}
texture->textureView = texture->texture->createTextureView(viewDesc);
texture->width = width;
texture->height = height;
texture->depth = depth;
texture->format = desc.format;
texture->viewDimension = viewDesc.dimension;
texture->descriptorIndex = g_textureDescriptorAllocator.allocate();
g_textureDescriptorSet->setTexture(texture->descriptorIndex, texture->texture, RenderTextureLayout::SHADER_READ, texture->textureView.get());
#ifdef _DEBUG
texture->texture->setName(fmt::format("Texture {:X}", g_memory.MapVirtual(texture)));
#endif
// Render targets/depth stencil textures are lazily created to have VRAM savings when the copy bypass optimization manages to work.
if (usage == 0)
texture->CreateTexture();
return texture;
}
@@ -2795,16 +2814,13 @@ static GuestSurface* CreateSurface(uint32_t width, uint32_t height, uint32_t for
surface->guestFormat = format;
surface->sampleCount = desc.multisampling.sampleCount;
if (desc.multisampling.sampleCount != RenderSampleCount::COUNT_1 && desc.format == RenderFormat::D32_FLOAT)
{
RenderTextureViewDesc viewDesc;
viewDesc.dimension = RenderTextureViewDimension::TEXTURE_2D;
viewDesc.format = RenderFormat::D32_FLOAT;
viewDesc.mipLevels = 1;
surface->textureView = surface->textureHolder->createTextureView(viewDesc);
surface->descriptorIndex = g_textureDescriptorAllocator.allocate();
g_textureDescriptorSet->setTexture(surface->descriptorIndex, surface->textureHolder.get(), RenderTextureLayout::SHADER_READ, surface->textureView.get());
}
RenderTextureViewDesc viewDesc;
viewDesc.dimension = RenderTextureViewDimension::TEXTURE_2D;
viewDesc.format = desc.format;
viewDesc.mipLevels = 1;
surface->textureView = surface->textureHolder->createTextureView(viewDesc);
surface->descriptorIndex = g_textureDescriptorAllocator.allocate();
g_textureDescriptorSet->setTexture(surface->descriptorIndex, surface->textureHolder.get(), RenderTextureLayout::SHADER_READ, surface->textureView.get());
#ifdef _DEBUG
surface->texture->setName(fmt::format("{} {:X}", desc.flags & RenderTextureFlag::RENDER_TARGET ? "Render Target" : "Depth Stencil", g_memory.MapVirtual(surface)));
@@ -2820,11 +2836,8 @@ static void FlushViewport()
if (g_dirtyStates.viewport)
{
auto viewport = g_viewport;
if (g_halfPixel)
{
viewport.x += 0.5f;
viewport.y += 0.5f;
}
viewport.x += 0.5f;
viewport.y += 0.5f;
if (viewport.minDepth > viewport.maxDepth)
std::swap(viewport.minDepth, viewport.maxDepth);
@@ -2848,13 +2861,6 @@ static void FlushViewport()
}
}
static bool SetHalfPixel(bool enable)
{
bool oldValue = g_halfPixel;
SetDirtyValue(g_dirtyStates.viewport, g_halfPixel, enable);
return oldValue;
}
static void StretchRect(GuestDevice* device, uint32_t flags, uint32_t, GuestTexture* texture)
{
RenderCommand cmd;
@@ -2864,105 +2870,43 @@ static void StretchRect(GuestDevice* device, uint32_t flags, uint32_t, GuestText
g_renderQueue.enqueue(cmd);
}
static void SetTextureInRenderThread(uint32_t index, GuestTexture* texture);
static void SetSurface(uint32_t index, GuestSurface* surface);
static void ProcStretchRect(const RenderCommand& cmd)
{
const auto& args = cmd.stretchRect;
const bool isDepthStencil = (args.flags & 0x4) != 0;
const auto surface = isDepthStencil ? g_depthStencil : g_renderTarget;
const bool multiSampling = surface->sampleCount != RenderSampleCount::COUNT_1;
RenderTextureLayout srcLayout;
RenderTextureLayout dstLayout;
// Erase previous pending command so it doesn't cause the texture to be overriden.
if (args.texture->sourceSurface != nullptr)
args.texture->sourceSurface->destinationTextures.erase(args.texture);
if (multiSampling)
args.texture->sourceSurface = surface;
surface->destinationTextures.emplace(args.texture);
// If the texture is assigned to any slots, set it again. This'll also push the barrier.
for (uint32_t i = 0; i < std::size(g_textures); i++)
{
if (isDepthStencil)
if (g_textures[i] == args.texture)
{
srcLayout = RenderTextureLayout::SHADER_READ;
dstLayout = RenderTextureLayout::DEPTH_WRITE;
}
else
{
srcLayout = RenderTextureLayout::RESOLVE_SOURCE;
dstLayout = RenderTextureLayout::RESOLVE_DEST;
// Set the original texture for MSAA textures as they always get resolved.
if (surface->sampleCount != RenderSampleCount::COUNT_1)
{
SetTextureInRenderThread(i, args.texture);
g_pendingMsaaResolves.emplace(surface);
}
else
{
SetSurface(i, surface);
}
}
}
else
{
srcLayout = RenderTextureLayout::COPY_SOURCE;
dstLayout = RenderTextureLayout::COPY_DEST;
}
AddBarrier(surface, srcLayout);
AddBarrier(args.texture, dstLayout);
FlushBarriers();
auto& commandList = g_commandLists[g_frame];
if (multiSampling)
{
if (isDepthStencil)
{
uint32_t pipelineIndex = 0;
switch (g_depthStencil->sampleCount)
{
case RenderSampleCount::COUNT_2:
pipelineIndex = 0;
break;
case RenderSampleCount::COUNT_4:
pipelineIndex = 1;
break;
case RenderSampleCount::COUNT_8:
pipelineIndex = 2;
break;
default:
assert(false && "Unsupported MSAA sample count");
break;
}
if (args.texture->framebuffer == nullptr)
{
RenderFramebufferDesc desc;
desc.depthAttachment = args.texture->texture;
args.texture->framebuffer = g_device->createFramebuffer(desc);
}
if (g_framebuffer != args.texture->framebuffer.get())
{
commandList->setFramebuffer(args.texture->framebuffer.get());
g_framebuffer = args.texture->framebuffer.get();
}
bool oldHalfPixel = SetHalfPixel(false);
FlushViewport();
commandList->setPipeline(g_resolveMsaaDepthPipelines[pipelineIndex].get());
commandList->setGraphicsPushConstants(0, &g_depthStencil->descriptorIndex, 0, sizeof(uint32_t));
commandList->drawInstanced(6, 1, 0, 0);
g_dirtyStates.renderTargetAndDepthStencil = true;
g_dirtyStates.pipelineState = true;
if (g_vulkan)
{
g_dirtyStates.depthBias = true; // Static depth bias in MSAA pipeline invalidates dynamic depth bias.
g_dirtyStates.vertexShaderConstants = true;
}
SetHalfPixel(oldHalfPixel);
}
else
{
commandList->resolveTexture(args.texture->texture, surface->texture);
}
}
else
{
commandList->copyTexture(args.texture->texture, surface->texture);
}
AddBarrier(args.texture, RenderTextureLayout::SHADER_READ);
// Remember to clear later.
g_pendingSurfaceCopies.emplace(surface);
}
static void SetDefaultViewport(GuestDevice* device, GuestSurface* surface)
@@ -3028,6 +2972,179 @@ static void ProcSetDepthStencilSurface(const RenderCommand& cmd)
SetDirtyValue(g_dirtyStates.pipelineState, g_pipelineState.depthStencilFormat, args.depthStencil != nullptr ? args.depthStencil->format : RenderFormat::UNKNOWN);
}
static bool PopulateBarriersForStretchRect(GuestSurface* renderTarget, GuestSurface* depthStencil)
{
bool addedAny = false;
for (const auto surface : { renderTarget, depthStencil })
{
if (surface != nullptr && !surface->destinationTextures.empty())
{
const bool multiSampling = surface->sampleCount != RenderSampleCount::COUNT_1;
RenderTextureLayout srcLayout;
RenderTextureLayout dstLayout;
if (multiSampling)
{
if (surface == depthStencil)
{
srcLayout = RenderTextureLayout::SHADER_READ;
dstLayout = RenderTextureLayout::DEPTH_WRITE;
}
else
{
srcLayout = RenderTextureLayout::RESOLVE_SOURCE;
dstLayout = RenderTextureLayout::RESOLVE_DEST;
}
}
else
{
srcLayout = RenderTextureLayout::COPY_SOURCE;
dstLayout = RenderTextureLayout::COPY_DEST;
}
AddBarrier(surface, srcLayout);
for (const auto texture : surface->destinationTextures)
{
// Need to create here...
if (texture->textureHolder == nullptr)
texture->CreateTexture();
AddBarrier(texture, dstLayout);
}
addedAny = true;
}
}
return addedAny;
}
static void ExecutePendingStretchRectCommands(GuestSurface* renderTarget, GuestSurface* depthStencil)
{
auto& commandList = g_commandLists[g_frame];
for (const auto surface : { renderTarget, depthStencil })
{
if (surface != nullptr && !surface->destinationTextures.empty())
{
const bool multiSampling = surface->sampleCount != RenderSampleCount::COUNT_1;
for (const auto texture : surface->destinationTextures)
{
// The texture doesn't need to be created at this point,
// since the barrier call would have already done it.
if (multiSampling)
{
if (surface == depthStencil)
{
uint32_t pipelineIndex = 0;
switch (surface->sampleCount)
{
case RenderSampleCount::COUNT_2:
pipelineIndex = 0;
break;
case RenderSampleCount::COUNT_4:
pipelineIndex = 1;
break;
case RenderSampleCount::COUNT_8:
pipelineIndex = 2;
break;
default:
assert(false && "Unsupported MSAA sample count");
break;
}
if (texture->framebuffer == nullptr)
{
RenderFramebufferDesc desc;
desc.depthAttachment = texture->texture;
texture->framebuffer = g_device->createFramebuffer(desc);
}
if (g_framebuffer != texture->framebuffer.get())
{
commandList->setFramebuffer(texture->framebuffer.get());
g_framebuffer = texture->framebuffer.get();
}
commandList->setPipeline(g_resolveMsaaDepthPipelines[pipelineIndex].get());
commandList->setViewports(RenderViewport(0.0f, 0.0f, float(texture->width), float(texture->height), 0.0f, 1.0f));
commandList->setScissors(RenderRect(0, 0, texture->width, texture->height));
commandList->setGraphicsPushConstants(0, &surface->descriptorIndex, 0, sizeof(uint32_t));
commandList->drawInstanced(6, 1, 0, 0);
g_dirtyStates.renderTargetAndDepthStencil = true;
g_dirtyStates.viewport = true;
g_dirtyStates.pipelineState = true;
g_dirtyStates.scissorRect = true;
if (g_vulkan)
{
g_dirtyStates.depthBias = true; // Static depth bias in MSAA pipeline invalidates dynamic depth bias.
g_dirtyStates.vertexShaderConstants = true;
}
}
else
{
commandList->resolveTexture(texture->texture, surface->texture);
}
}
else
{
commandList->copyTexture(texture->texture, surface->texture);
}
texture->sourceSurface = nullptr;
// Check if any texture slots had this texture assigned, and make it point back at the original texture.
for (uint32_t i = 0; i < std::size(g_textures); i++)
{
if (g_textures[i] == texture)
SetTextureInRenderThread(i, texture);
}
}
surface->destinationTextures.clear();
}
}
}
static void ProcExecutePendingStretchRectCommands(const RenderCommand& cmd)
{
bool foundAny = false;
for (const auto surface : g_pendingSurfaceCopies)
{
// Depth stencil textures in this game are guaranteed to be transient.
if (surface->format != RenderFormat::D32_FLOAT)
foundAny |= PopulateBarriersForStretchRect(surface, nullptr);
}
if (foundAny)
{
FlushBarriers();
for (const auto surface : g_pendingSurfaceCopies)
{
if (surface->format != RenderFormat::D32_FLOAT)
ExecutePendingStretchRectCommands(surface, nullptr);
for (const auto texture : surface->destinationTextures)
texture->sourceSurface = nullptr;
surface->destinationTextures.clear();
}
}
g_pendingSurfaceCopies.clear();
g_pendingMsaaResolves.clear();
}
static void SetFramebuffer(GuestSurface* renderTarget, GuestSurface* depthStencil, bool settingForClear)
{
if (settingForClear || g_dirtyStates.renderTargetAndDepthStencil)
@@ -3106,6 +3223,12 @@ static void ProcClear(const RenderCommand& cmd)
{
const auto& args = cmd.clear;
if (PopulateBarriersForStretchRect(g_renderTarget, g_depthStencil))
{
FlushBarriers();
ExecutePendingStretchRectCommands(g_renderTarget, g_depthStencil);
}
AddBarrier(g_renderTarget, RenderTextureLayout::COLOR_WRITE);
AddBarrier(g_depthStencil, RenderTextureLayout::DEPTH_WRITE);
FlushBarriers();
@@ -3194,22 +3317,59 @@ static void SetTexture(GuestDevice* device, uint32_t index, GuestTexture* textur
g_renderQueue.enqueue(cmd);
}
static void SetTextureInRenderThread(uint32_t index, GuestTexture* texture)
{
// Only may happen for render target/depth stencil textures.
if (texture != nullptr && texture->textureHolder == nullptr)
texture->CreateTexture();
AddBarrier(texture, RenderTextureLayout::SHADER_READ);
auto viewDimension = texture != nullptr ? texture->viewDimension : RenderTextureViewDimension::UNKNOWN;
SetDirtyValue(g_dirtyStates.sharedConstants, g_sharedConstants.texture2DIndices[index],
viewDimension == RenderTextureViewDimension::TEXTURE_2D ? texture->descriptorIndex : TEXTURE_DESCRIPTOR_NULL_TEXTURE_2D);
SetDirtyValue(g_dirtyStates.sharedConstants, g_sharedConstants.texture3DIndices[index], texture != nullptr &&
viewDimension == RenderTextureViewDimension::TEXTURE_3D ? texture->descriptorIndex : TEXTURE_DESCRIPTOR_NULL_TEXTURE_3D);
SetDirtyValue(g_dirtyStates.sharedConstants, g_sharedConstants.textureCubeIndices[index], texture != nullptr &&
viewDimension == RenderTextureViewDimension::TEXTURE_CUBE ? texture->descriptorIndex : TEXTURE_DESCRIPTOR_NULL_TEXTURE_CUBE);
}
static void SetSurface(uint32_t index, GuestSurface* surface)
{
AddBarrier(surface, RenderTextureLayout::SHADER_READ);
SetDirtyValue(g_dirtyStates.sharedConstants, g_sharedConstants.texture2DIndices[index], surface->descriptorIndex);
SetDirtyValue(g_dirtyStates.sharedConstants, g_sharedConstants.texture3DIndices[index], uint32_t(TEXTURE_DESCRIPTOR_NULL_TEXTURE_3D));
SetDirtyValue(g_dirtyStates.sharedConstants, g_sharedConstants.textureCubeIndices[index], uint32_t(TEXTURE_DESCRIPTOR_NULL_TEXTURE_CUBE));
}
static void ProcSetTexture(const RenderCommand& cmd)
{
const auto& args = cmd.setTexture;
AddBarrier(args.texture, RenderTextureLayout::SHADER_READ);
// If a pending copy operation is detected, set the source surface. The indices will be fixed later if flushing is necessary.
bool shouldSetTexture = true;
if (args.texture != nullptr && args.texture->sourceSurface != nullptr)
{
// MSAA surfaces need to be resolved and cannot be used directly.
if (args.texture->sourceSurface->sampleCount != RenderSampleCount::COUNT_1)
{
g_pendingMsaaResolves.emplace(args.texture->sourceSurface);
}
else
{
SetSurface(args.index, args.texture->sourceSurface);
shouldSetTexture = false;
}
}
auto viewDimension = args.texture != nullptr ? args.texture->viewDimension : RenderTextureViewDimension::UNKNOWN;
if (shouldSetTexture)
SetTextureInRenderThread(args.index, args.texture);
SetDirtyValue(g_dirtyStates.sharedConstants, g_sharedConstants.texture2DIndices[args.index],
viewDimension == RenderTextureViewDimension::TEXTURE_2D ? args.texture->descriptorIndex : TEXTURE_DESCRIPTOR_NULL_TEXTURE_2D);
SetDirtyValue(g_dirtyStates.sharedConstants, g_sharedConstants.texture3DIndices[args.index], args.texture != nullptr &&
viewDimension == RenderTextureViewDimension::TEXTURE_3D ? args.texture->descriptorIndex : TEXTURE_DESCRIPTOR_NULL_TEXTURE_3D);
SetDirtyValue(g_dirtyStates.sharedConstants, g_sharedConstants.textureCubeIndices[args.index], args.texture != nullptr &&
viewDimension == RenderTextureViewDimension::TEXTURE_CUBE ? args.texture->descriptorIndex : TEXTURE_DESCRIPTOR_NULL_TEXTURE_CUBE);
g_textures[args.index] = args.texture;
}
static void SetScissorRect(GuestDevice* device, GuestRect* rect)
@@ -3815,9 +3975,34 @@ static void FlushRenderStateForRenderThread()
auto renderTarget = g_pipelineState.colorWriteEnable ? g_renderTarget : nullptr;
auto depthStencil = g_pipelineState.zEnable ? g_depthStencil : nullptr;
bool foundAny = PopulateBarriersForStretchRect(renderTarget, depthStencil);
for (const auto surface : g_pendingMsaaResolves)
{
bool isDepthStencil = (surface->format == RenderFormat::D32_FLOAT);
foundAny |= PopulateBarriersForStretchRect(isDepthStencil ? nullptr : surface, isDepthStencil ? surface : nullptr);
}
if (foundAny)
{
FlushBarriers();
ExecutePendingStretchRectCommands(renderTarget, depthStencil);
for (const auto surface : g_pendingMsaaResolves)
{
bool isDepthStencil = (surface->format == RenderFormat::D32_FLOAT);
ExecutePendingStretchRectCommands(isDepthStencil ? nullptr : surface, isDepthStencil ? surface : nullptr);
}
}
if (!g_pendingMsaaResolves.empty())
g_pendingMsaaResolves.clear();
AddBarrier(renderTarget, RenderTextureLayout::COLOR_WRITE);
AddBarrier(depthStencil, RenderTextureLayout::DEPTH_WRITE);
FlushBarriers();
SetFramebuffer(renderTarget, depthStencil, false);
FlushViewport();
@@ -4580,35 +4765,36 @@ static std::thread g_renderThread([]
auto& cmd = commands[i];
switch (cmd.type)
{
case RenderCommandType::SetRenderState: ProcSetRenderState(cmd); break;
case RenderCommandType::DestructResource: ProcDestructResource(cmd); break;
case RenderCommandType::UnlockTextureRect: ProcUnlockTextureRect(cmd); break;
case RenderCommandType::UnlockBuffer16: ProcUnlockBuffer16(cmd); break;
case RenderCommandType::UnlockBuffer32: ProcUnlockBuffer32(cmd); break;
case RenderCommandType::DrawImGui: ProcDrawImGui(cmd); break;
case RenderCommandType::ExecuteCommandList: ProcExecuteCommandList(cmd); break;
case RenderCommandType::BeginCommandList: ProcBeginCommandList(cmd); break;
case RenderCommandType::StretchRect: ProcStretchRect(cmd); break;
case RenderCommandType::SetRenderTarget: ProcSetRenderTarget(cmd); break;
case RenderCommandType::SetDepthStencilSurface: ProcSetDepthStencilSurface(cmd); break;
case RenderCommandType::Clear: ProcClear(cmd); break;
case RenderCommandType::SetViewport: ProcSetViewport(cmd); break;
case RenderCommandType::SetTexture: ProcSetTexture(cmd); break;
case RenderCommandType::SetScissorRect: ProcSetScissorRect(cmd); break;
case RenderCommandType::SetSamplerState: ProcSetSamplerState(cmd); break;
case RenderCommandType::SetBooleans: ProcSetBooleans(cmd); break;
case RenderCommandType::SetVertexShaderConstants: ProcSetVertexShaderConstants(cmd); break;
case RenderCommandType::SetPixelShaderConstants: ProcSetPixelShaderConstants(cmd); break;
case RenderCommandType::AddPipeline: ProcAddPipeline(cmd); break;
case RenderCommandType::DrawPrimitive: ProcDrawPrimitive(cmd); break;
case RenderCommandType::DrawIndexedPrimitive: ProcDrawIndexedPrimitive(cmd); break;
case RenderCommandType::DrawPrimitiveUP: ProcDrawPrimitiveUP(cmd); break;
case RenderCommandType::SetVertexDeclaration: ProcSetVertexDeclaration(cmd); break;
case RenderCommandType::SetVertexShader: ProcSetVertexShader(cmd); break;
case RenderCommandType::SetStreamSource: ProcSetStreamSource(cmd); break;
case RenderCommandType::SetIndices: ProcSetIndices(cmd); break;
case RenderCommandType::SetPixelShader: ProcSetPixelShader(cmd); break;
default: assert(false && "Unrecognized render command type."); break;
case RenderCommandType::SetRenderState: ProcSetRenderState(cmd); break;
case RenderCommandType::DestructResource: ProcDestructResource(cmd); break;
case RenderCommandType::UnlockTextureRect: ProcUnlockTextureRect(cmd); break;
case RenderCommandType::UnlockBuffer16: ProcUnlockBuffer16(cmd); break;
case RenderCommandType::UnlockBuffer32: ProcUnlockBuffer32(cmd); break;
case RenderCommandType::DrawImGui: ProcDrawImGui(cmd); break;
case RenderCommandType::ExecuteCommandList: ProcExecuteCommandList(cmd); break;
case RenderCommandType::BeginCommandList: ProcBeginCommandList(cmd); break;
case RenderCommandType::StretchRect: ProcStretchRect(cmd); break;
case RenderCommandType::SetRenderTarget: ProcSetRenderTarget(cmd); break;
case RenderCommandType::SetDepthStencilSurface: ProcSetDepthStencilSurface(cmd); break;
case RenderCommandType::ExecutePendingStretchRectCommands: ProcExecutePendingStretchRectCommands(cmd); break;
case RenderCommandType::Clear: ProcClear(cmd); break;
case RenderCommandType::SetViewport: ProcSetViewport(cmd); break;
case RenderCommandType::SetTexture: ProcSetTexture(cmd); break;
case RenderCommandType::SetScissorRect: ProcSetScissorRect(cmd); break;
case RenderCommandType::SetSamplerState: ProcSetSamplerState(cmd); break;
case RenderCommandType::SetBooleans: ProcSetBooleans(cmd); break;
case RenderCommandType::SetVertexShaderConstants: ProcSetVertexShaderConstants(cmd); break;
case RenderCommandType::SetPixelShaderConstants: ProcSetPixelShaderConstants(cmd); break;
case RenderCommandType::AddPipeline: ProcAddPipeline(cmd); break;
case RenderCommandType::DrawPrimitive: ProcDrawPrimitive(cmd); break;
case RenderCommandType::DrawIndexedPrimitive: ProcDrawIndexedPrimitive(cmd); break;
case RenderCommandType::DrawPrimitiveUP: ProcDrawPrimitiveUP(cmd); break;
case RenderCommandType::SetVertexDeclaration: ProcSetVertexDeclaration(cmd); break;
case RenderCommandType::SetVertexShader: ProcSetVertexShader(cmd); break;
case RenderCommandType::SetStreamSource: ProcSetStreamSource(cmd); break;
case RenderCommandType::SetIndices: ProcSetIndices(cmd); break;
case RenderCommandType::SetPixelShader: ProcSetPixelShader(cmd); break;
default: assert(false && "Unrecognized render command type."); break;
}
}
@@ -6772,6 +6958,52 @@ PPC_FUNC(sub_825E2F78)
__imp__sub_825E2F78(ctx, base);
}
// Game shares surfaces with identical descriptions. We don't want to share shadow maps,
// so we can set its format to a depth format that still resolves to the same type in recomp,
// but manages to keep the surfaces actually separated in guest code.
void FxShadowMapInitMidAsmHook(PPCRegister& r11)
{
uint8_t* base = g_memory.base;
uint32_t surface = PPC_LOAD_U32(PPC_LOAD_U32(PPC_LOAD_U32(r11.u32 + 0x24) + 0x4));
PPC_STORE_U32(surface + 0x20, D3DFMT_D24FS8);
}
// Re-render objects in the terrain shadow map instead of copying the texture.
static bool g_jumpOverStretchRect;
void FxShadowMapNoTerrainMidAsmHook(PPCRegister& r4, PPCRegister& r30)
{
// Set the no terrain shadow map as the render target.
uint8_t* base = g_memory.base;
r4.u64 = PPC_LOAD_U32(r30.u32 + 0x58);
}
bool FxShadowMapMidAsmHook(PPCRegister& r4, PPCRegister& r5, PPCRegister& r6, PPCRegister& r30)
{
if (g_jumpOverStretchRect)
{
// Reset for the next time shadow maps get rendered.
g_jumpOverStretchRect = false;
// Jump over the stretch rect call.
return false;
}
else
{
// Mark to jump over the stretch call the next time.
g_jumpOverStretchRect = true;
// Jump to the beginning. Set registers accordingly to set the terrain shadow map as the render target.
uint8_t* base = g_memory.base;
r6.u64 = 0;
r5.u64 = 0;
r4.u64 = PPC_LOAD_U32(r30.u32 + 0x50);
return true;
}
}
GUEST_FUNCTION_HOOK(sub_82BD99B0, CreateDevice);
GUEST_FUNCTION_HOOK(sub_82BE6230, DestructResource);
+6
View File
@@ -154,10 +154,15 @@ struct GuestBaseTexture : GuestResource
struct GuestTexture : GuestBaseTexture
{
uint32_t depth = 0;
uint32_t levels = 0;
RenderTextureViewDimension viewDimension = RenderTextureViewDimension::UNKNOWN;
RenderComponentMapping componentMapping;
void* mappedMemory = nullptr;
std::unique_ptr<RenderFramebuffer> framebuffer;
std::unique_ptr<GuestTexture> patchedTexture;
struct GuestSurface* sourceSurface = nullptr;
void CreateTexture();
};
struct GuestLockedRect
@@ -205,6 +210,7 @@ struct GuestSurface : GuestBaseTexture
uint32_t guestFormat = 0;
ankerl::unordered_dense::map<const RenderTexture*, std::unique_ptr<RenderFramebuffer>> framebuffers;
RenderSampleCounts sampleCount = RenderSampleCount::COUNT_1;
ankerl::unordered_dense::set<GuestTexture*> destinationTextures;
};
enum GuestDeclType
@@ -8,7 +8,7 @@
#include <user/paths.h>
#include <app.h>
static bool g_faderBegun = false;
static std::atomic<bool> g_faderBegun = false;
bool g_quitMessageOpen = false;
static int g_quitMessageResult = -1;
@@ -16,39 +16,29 @@ static int g_quitMessageResult = -1;
static std::atomic<bool> g_corruptSaveMessageOpen = false;
static int g_corruptSaveMessageResult = -1;
static bool g_corruptAchievementsMessageOpen = false;
static std::atomic<bool> g_corruptAchievementsMessageOpen = false;
static int g_corruptAchievementsMessageResult = -1;
static bool g_updateAvailableMessageOpen = false;
static std::atomic<bool> g_updateAvailableMessageOpen = false;
static int g_updateAvailableMessageResult = -1;
static bool ProcessQuitMessage()
{
if (g_corruptSaveMessageOpen)
return false;
if (!g_quitMessageOpen)
return false;
if (g_faderBegun)
return true;
std::array<std::string, 2> options = { Localise("Common_Yes"), Localise("Common_No") };
if (MessageWindow::Open(Localise("Title_Message_Quit"), &g_quitMessageResult, options, 1) == MSG_CLOSED)
{
switch (g_quitMessageResult)
if (!g_quitMessageResult)
{
case 0:
Fader::FadeOut(1, []() { App::Exit(); });
g_faderBegun = true;
break;
case 1:
g_quitMessageOpen = false;
g_quitMessageResult = -1;
break;
Fader::FadeOut(1, []() { App::Exit(); });
g_faderBegun = true;
}
g_quitMessageOpen = false;
g_quitMessageResult = -1;
}
return true;
@@ -86,6 +76,7 @@ static bool ProcessCorruptAchievementsMessage()
AchievementManager::Save(true);
g_corruptAchievementsMessageOpen = false;
g_corruptAchievementsMessageOpen.notify_one();
g_corruptAchievementsMessageResult = -1;
}
@@ -97,9 +88,6 @@ static bool ProcessUpdateAvailableMessage()
if (!g_updateAvailableMessageOpen)
return false;
if (g_faderBegun)
return true;
std::array<std::string, 2> options = { Localise("Common_Yes"), Localise("Common_No") };
if (MessageWindow::Open(Localise("Title_Message_UpdateAvailable"), &g_updateAvailableMessageResult, options) == MSG_CLOSED)
@@ -119,6 +107,7 @@ static bool ProcessUpdateAvailableMessage()
}
g_updateAvailableMessageOpen = false;
g_updateAvailableMessageOpen.notify_one();
g_updateAvailableMessageResult = -1;
}
@@ -137,6 +126,24 @@ PPC_FUNC(sub_822C55B0)
ctx.r3.u32 = 0;
}
void PressStartSaveLoadThreadMidAsmHook()
{
if (UpdateChecker::check() == UpdateChecker::Result::UpdateAvailable)
{
g_updateAvailableMessageOpen = true;
g_updateAvailableMessageOpen.wait(true);
g_faderBegun.wait(true);
}
AchievementManager::Load();
if (AchievementManager::Status != EAchStatus::Success)
{
g_corruptAchievementsMessageOpen = true;
g_corruptAchievementsMessageOpen.wait(true);
}
}
// SWA::CTitleStateIntro::Update
PPC_FUNC_IMPL(__imp__sub_82587E50);
PPC_FUNC(sub_82587E50)
@@ -151,21 +158,7 @@ PPC_FUNC(sub_82587E50)
{
if (auto pInputState = SWA::CInputState::GetInstance())
{
auto& rPadState = pInputState->GetPadState();
auto isAccepted = rPadState.IsTapped(SWA::eKeyState_A) || rPadState.IsTapped(SWA::eKeyState_Start);
auto isDeclined = rPadState.IsTapped(SWA::eKeyState_B);
if (isAccepted)
{
g_updateAvailableMessageOpen = UpdateChecker::check() == UpdateChecker::Result::UpdateAvailable;
AchievementManager::Load();
if (AchievementManager::Status != EAchStatus::Success)
g_corruptAchievementsMessageOpen = true;
}
if (isDeclined)
if (pInputState->GetPadState().IsTapped(SWA::eKeyState_B))
g_quitMessageOpen = true;
}
+1 -1
View File
@@ -197,7 +197,7 @@ static void DrawAchievement(int rowIndex, float yOffset, Achievement& achievemen
ImVec2 marqueeMin = { textMarqueeX, min.y };
ImVec2 marqueeMax = { max.x - Scale(10) /* timestamp margin X */, max.y };
SetMarqueeFade(marqueeMin, marqueeMax, Scale(32));
SetHorizontalMarqueeFade(marqueeMin, marqueeMax, Scale(32));
if (isSelected && textX + textSize.x >= max.x - Scale(10))
{
+14 -2
View File
@@ -80,7 +80,7 @@ void ResetTextSkew()
SetScale({ 1.0f, 1.0f });
}
void SetMarqueeFade(ImVec2 min, ImVec2 max, float fadeScale)
void SetHorizontalMarqueeFade(ImVec2 min, ImVec2 max, float fadeScale)
{
auto callbackData = AddImGuiCallback(ImGuiCallback::SetMarqueeFade);
callbackData->setMarqueeFade.boundsMin[0] = min.x;
@@ -88,10 +88,22 @@ void SetMarqueeFade(ImVec2 min, ImVec2 max, float fadeScale)
callbackData->setMarqueeFade.boundsMax[0] = max.x;
callbackData->setMarqueeFade.boundsMax[1] = max.y;
SetShaderModifier(IMGUI_SHADER_MODIFIER_MARQUEE_FADE);
SetShaderModifier(IMGUI_SHADER_MODIFIER_HORIZONTAL_MARQUEE_FADE);
SetScale({ fadeScale, 1.0f });
}
void SetVerticalMarqueeFade(ImVec2 min, ImVec2 max, float fadeScale)
{
auto callbackData = AddImGuiCallback(ImGuiCallback::SetMarqueeFade);
callbackData->setMarqueeFade.boundsMin[0] = min.x;
callbackData->setMarqueeFade.boundsMin[1] = min.y;
callbackData->setMarqueeFade.boundsMax[0] = max.x;
callbackData->setMarqueeFade.boundsMax[1] = max.y;
SetShaderModifier(IMGUI_SHADER_MODIFIER_VERTICAL_MARQUEE_FADE);
SetScale({ 1.0f, fadeScale });
}
void ResetMarqueeFade()
{
ResetGradient();
+2 -1
View File
@@ -42,7 +42,8 @@ void SetOrigin(ImVec2 origin);
void SetScale(ImVec2 scale);
void SetTextSkew(float yCenter, float skewScale);
void ResetTextSkew();
void SetMarqueeFade(ImVec2 min, ImVec2 max, float fadeScale);
void SetHorizontalMarqueeFade(ImVec2 min, ImVec2 max, float fadeScale);
void SetVerticalMarqueeFade(ImVec2 min, ImVec2 max, float fadeScale);
void ResetMarqueeFade();
void SetOutline(float outline);
void ResetOutline();
+1 -1
View File
@@ -797,7 +797,7 @@ static void DrawDescriptionContainer()
ImVec2 textMin = { g_aspectRatioOffsetX + Scale(CONTAINER_X), textPos.y };
ImVec2 textMax = { g_aspectRatioOffsetX + Scale(CONTAINER_X) + Scale(CONTAINER_WIDTH), g_aspectRatioOffsetY + Scale(CONTAINER_Y) + Scale(CONTAINER_HEIGHT) };
SetMarqueeFade(textMin, textMax, Scale(32));
SetHorizontalMarqueeFade(textMin, textMax, Scale(32));
DrawTextWithMarquee(g_seuratFont, fontSize, textPos, textMin, textMax, colWhite, g_creditsStr.c_str(), g_installerEndTime, 0.9, Scale(200));
ResetMarqueeFade();
}
+136 -136
View File
@@ -39,7 +39,7 @@ CONFIG_DEFINE_ENUM_TEMPLATE(EControllerIcons)
CONFIG_DEFINE_ENUM_TEMPLATE(SDL_Scancode)
{
{ "UNKNOWN", SDL_SCANCODE_UNKNOWN },
{ "???", SDL_SCANCODE_UNKNOWN },
{ "A", SDL_SCANCODE_A },
{ "B", SDL_SCANCODE_B },
{ "C", SDL_SCANCODE_C },
@@ -83,17 +83,17 @@ CONFIG_DEFINE_ENUM_TEMPLATE(SDL_Scancode)
{ "SPACE", SDL_SCANCODE_SPACE },
{ "MINUS", SDL_SCANCODE_MINUS },
{ "EQUALS", SDL_SCANCODE_EQUALS },
{ "LEFTBRACKET", SDL_SCANCODE_LEFTBRACKET },
{ "RIGHTBRACKET", SDL_SCANCODE_RIGHTBRACKET },
{ "LEFT BRACKET", SDL_SCANCODE_LEFTBRACKET },
{ "RIGHT BRACKET", SDL_SCANCODE_RIGHTBRACKET },
{ "BACKSLASH", SDL_SCANCODE_BACKSLASH },
{ "NONUSHASH", SDL_SCANCODE_NONUSHASH },
{ "NON-US HASH", SDL_SCANCODE_NONUSHASH },
{ "SEMICOLON", SDL_SCANCODE_SEMICOLON },
{ "APOSTROPHE", SDL_SCANCODE_APOSTROPHE },
{ "GRAVE", SDL_SCANCODE_GRAVE },
{ "COMMA", SDL_SCANCODE_COMMA },
{ "PERIOD", SDL_SCANCODE_PERIOD },
{ "SLASH", SDL_SCANCODE_SLASH },
{ "CAPSLOCK", SDL_SCANCODE_CAPSLOCK },
{ "CAPS LOCK", SDL_SCANCODE_CAPSLOCK },
{ "F1", SDL_SCANCODE_F1 },
{ "F2", SDL_SCANCODE_F2 },
{ "F3", SDL_SCANCODE_F3 },
@@ -106,40 +106,40 @@ CONFIG_DEFINE_ENUM_TEMPLATE(SDL_Scancode)
{ "F10", SDL_SCANCODE_F10 },
{ "F11", SDL_SCANCODE_F11 },
{ "F12", SDL_SCANCODE_F12 },
{ "PRINTSCREEN", SDL_SCANCODE_PRINTSCREEN },
{ "SCROLLLOCK", SDL_SCANCODE_SCROLLLOCK },
{ "PRINT SCREEN", SDL_SCANCODE_PRINTSCREEN },
{ "SCROLL LOCK", SDL_SCANCODE_SCROLLLOCK },
{ "PAUSE", SDL_SCANCODE_PAUSE },
{ "INSERT", SDL_SCANCODE_INSERT },
{ "HOME", SDL_SCANCODE_HOME },
{ "PAGEUP", SDL_SCANCODE_PAGEUP },
{ "PAGE UP", SDL_SCANCODE_PAGEUP },
{ "DELETE", SDL_SCANCODE_DELETE },
{ "END", SDL_SCANCODE_END },
{ "PAGEDOWN", SDL_SCANCODE_PAGEDOWN },
{ "PAGE DOWN", SDL_SCANCODE_PAGEDOWN },
{ "RIGHT", SDL_SCANCODE_RIGHT },
{ "LEFT", SDL_SCANCODE_LEFT },
{ "DOWN", SDL_SCANCODE_DOWN },
{ "UP", SDL_SCANCODE_UP },
{ "NUMLOCKCLEAR", SDL_SCANCODE_NUMLOCKCLEAR },
{ "KP_DIVIDE", SDL_SCANCODE_KP_DIVIDE },
{ "KP_MULTIPLY", SDL_SCANCODE_KP_MULTIPLY },
{ "KP_MINUS", SDL_SCANCODE_KP_MINUS },
{ "KP_PLUS", SDL_SCANCODE_KP_PLUS },
{ "KP_ENTER", SDL_SCANCODE_KP_ENTER },
{ "KP_1", SDL_SCANCODE_KP_1 },
{ "KP_2", SDL_SCANCODE_KP_2 },
{ "KP_3", SDL_SCANCODE_KP_3 },
{ "KP_4", SDL_SCANCODE_KP_4 },
{ "KP_5", SDL_SCANCODE_KP_5 },
{ "KP_6", SDL_SCANCODE_KP_6 },
{ "KP_7", SDL_SCANCODE_KP_7 },
{ "KP_8", SDL_SCANCODE_KP_8 },
{ "KP_9", SDL_SCANCODE_KP_9 },
{ "KP_0", SDL_SCANCODE_KP_0 },
{ "KP_PERIOD", SDL_SCANCODE_KP_PERIOD },
{ "NONUSBACKSLASH", SDL_SCANCODE_NONUSBACKSLASH },
{ "NUM LOCK", SDL_SCANCODE_NUMLOCKCLEAR },
{ "KP DIVIDE", SDL_SCANCODE_KP_DIVIDE },
{ "KP MULTIPLY", SDL_SCANCODE_KP_MULTIPLY },
{ "KP MINUS", SDL_SCANCODE_KP_MINUS },
{ "KP PLUS", SDL_SCANCODE_KP_PLUS },
{ "KP ENTER", SDL_SCANCODE_KP_ENTER },
{ "KP 1", SDL_SCANCODE_KP_1 },
{ "KP 2", SDL_SCANCODE_KP_2 },
{ "KP 3", SDL_SCANCODE_KP_3 },
{ "KP 4", SDL_SCANCODE_KP_4 },
{ "KP 5", SDL_SCANCODE_KP_5 },
{ "KP 6", SDL_SCANCODE_KP_6 },
{ "KP 7", SDL_SCANCODE_KP_7 },
{ "KP 8", SDL_SCANCODE_KP_8 },
{ "KP 9", SDL_SCANCODE_KP_9 },
{ "KP 0", SDL_SCANCODE_KP_0 },
{ "KP PERIOD", SDL_SCANCODE_KP_PERIOD },
{ "NON-US BACKSLASH", SDL_SCANCODE_NONUSBACKSLASH },
{ "APPLICATION", SDL_SCANCODE_APPLICATION },
{ "POWER", SDL_SCANCODE_POWER },
{ "KP_EQUALS", SDL_SCANCODE_KP_EQUALS },
{ "KP EQUALS", SDL_SCANCODE_KP_EQUALS },
{ "F13", SDL_SCANCODE_F13 },
{ "F14", SDL_SCANCODE_F14 },
{ "F15", SDL_SCANCODE_F15 },
@@ -164,128 +164,128 @@ CONFIG_DEFINE_ENUM_TEMPLATE(SDL_Scancode)
{ "PASTE", SDL_SCANCODE_PASTE },
{ "FIND", SDL_SCANCODE_FIND },
{ "MUTE", SDL_SCANCODE_MUTE },
{ "VOLUMEUP", SDL_SCANCODE_VOLUMEUP },
{ "VOLUMEDOWN", SDL_SCANCODE_VOLUMEDOWN },
{ "KP_COMMA", SDL_SCANCODE_KP_COMMA },
{ "KP_EQUALSAS400", SDL_SCANCODE_KP_EQUALSAS400 },
{ "INTERNATIONAL1", SDL_SCANCODE_INTERNATIONAL1 },
{ "INTERNATIONAL2", SDL_SCANCODE_INTERNATIONAL2 },
{ "INTERNATIONAL3", SDL_SCANCODE_INTERNATIONAL3 },
{ "INTERNATIONAL4", SDL_SCANCODE_INTERNATIONAL4 },
{ "INTERNATIONAL5", SDL_SCANCODE_INTERNATIONAL5 },
{ "INTERNATIONAL6", SDL_SCANCODE_INTERNATIONAL6 },
{ "INTERNATIONAL7", SDL_SCANCODE_INTERNATIONAL7 },
{ "INTERNATIONAL8", SDL_SCANCODE_INTERNATIONAL8 },
{ "INTERNATIONAL9", SDL_SCANCODE_INTERNATIONAL9 },
{ "LANG1", SDL_SCANCODE_LANG1 },
{ "LANG2", SDL_SCANCODE_LANG2 },
{ "LANG3", SDL_SCANCODE_LANG3 },
{ "LANG4", SDL_SCANCODE_LANG4 },
{ "LANG5", SDL_SCANCODE_LANG5 },
{ "LANG6", SDL_SCANCODE_LANG6 },
{ "LANG7", SDL_SCANCODE_LANG7 },
{ "LANG8", SDL_SCANCODE_LANG8 },
{ "LANG9", SDL_SCANCODE_LANG9 },
{ "ALTERASE", SDL_SCANCODE_ALTERASE },
{ "SYSREQ", SDL_SCANCODE_SYSREQ },
{ "VOLUME UP", SDL_SCANCODE_VOLUMEUP },
{ "VOLUME DOWN", SDL_SCANCODE_VOLUMEDOWN },
{ "KP COMMA", SDL_SCANCODE_KP_COMMA },
{ "KP EQUALS AS400", SDL_SCANCODE_KP_EQUALSAS400 },
{ "INTERNATIONAL 1", SDL_SCANCODE_INTERNATIONAL1 },
{ "INTERNATIONAL 2", SDL_SCANCODE_INTERNATIONAL2 },
{ "INTERNATIONAL 3", SDL_SCANCODE_INTERNATIONAL3 },
{ "INTERNATIONAL 4", SDL_SCANCODE_INTERNATIONAL4 },
{ "INTERNATIONAL 5", SDL_SCANCODE_INTERNATIONAL5 },
{ "INTERNATIONAL 6", SDL_SCANCODE_INTERNATIONAL6 },
{ "INTERNATIONAL 7", SDL_SCANCODE_INTERNATIONAL7 },
{ "INTERNATIONAL 8", SDL_SCANCODE_INTERNATIONAL8 },
{ "INTERNATIONAL 9", SDL_SCANCODE_INTERNATIONAL9 },
{ "LANG 1", SDL_SCANCODE_LANG1 },
{ "LANG 2", SDL_SCANCODE_LANG2 },
{ "LANG 3", SDL_SCANCODE_LANG3 },
{ "LANG 4", SDL_SCANCODE_LANG4 },
{ "LANG 5", SDL_SCANCODE_LANG5 },
{ "LANG 6", SDL_SCANCODE_LANG6 },
{ "LANG 7", SDL_SCANCODE_LANG7 },
{ "LANG 8", SDL_SCANCODE_LANG8 },
{ "LANG 9", SDL_SCANCODE_LANG9 },
{ "ALT ERASE", SDL_SCANCODE_ALTERASE },
{ "SYS REQ", SDL_SCANCODE_SYSREQ },
{ "CANCEL", SDL_SCANCODE_CANCEL },
{ "CLEAR", SDL_SCANCODE_CLEAR },
{ "PRIOR", SDL_SCANCODE_PRIOR },
{ "RETURN2", SDL_SCANCODE_RETURN2 },
{ "RETURN 2", SDL_SCANCODE_RETURN2 },
{ "SEPARATOR", SDL_SCANCODE_SEPARATOR },
{ "OUT", SDL_SCANCODE_OUT },
{ "OPER", SDL_SCANCODE_OPER },
{ "CLEARAGAIN", SDL_SCANCODE_CLEARAGAIN },
{ "CRSEL", SDL_SCANCODE_CRSEL },
{ "EXSEL", SDL_SCANCODE_EXSEL },
{ "KP_00", SDL_SCANCODE_KP_00 },
{ "KP_000", SDL_SCANCODE_KP_000 },
{ "THOUSANDSSEPARATOR", SDL_SCANCODE_THOUSANDSSEPARATOR },
{ "DECIMALSEPARATOR", SDL_SCANCODE_DECIMALSEPARATOR },
{ "CURRENCYUNIT", SDL_SCANCODE_CURRENCYUNIT },
{ "CURRENCYSUBUNIT", SDL_SCANCODE_CURRENCYSUBUNIT },
{ "KP_LEFTPAREN", SDL_SCANCODE_KP_LEFTPAREN },
{ "KP_RIGHTPAREN", SDL_SCANCODE_KP_RIGHTPAREN },
{ "KP_LEFTBRACE", SDL_SCANCODE_KP_LEFTBRACE },
{ "KP_RIGHTBRACE", SDL_SCANCODE_KP_RIGHTBRACE },
{ "KP_TAB", SDL_SCANCODE_KP_TAB },
{ "KP_BACKSPACE", SDL_SCANCODE_KP_BACKSPACE },
{ "KP_A", SDL_SCANCODE_KP_A },
{ "KP_B", SDL_SCANCODE_KP_B },
{ "KP_C", SDL_SCANCODE_KP_C },
{ "KP_D", SDL_SCANCODE_KP_D },
{ "KP_E", SDL_SCANCODE_KP_E },
{ "KP_F", SDL_SCANCODE_KP_F },
{ "KP_XOR", SDL_SCANCODE_KP_XOR },
{ "KP_POWER", SDL_SCANCODE_KP_POWER },
{ "KP_PERCENT", SDL_SCANCODE_KP_PERCENT },
{ "KP_LESS", SDL_SCANCODE_KP_LESS },
{ "KP_GREATER", SDL_SCANCODE_KP_GREATER },
{ "KP_AMPERSAND", SDL_SCANCODE_KP_AMPERSAND },
{ "KP_DBLAMPERSAND", SDL_SCANCODE_KP_DBLAMPERSAND },
{ "KP_VERTICALBAR", SDL_SCANCODE_KP_VERTICALBAR },
{ "KP_DBLVERTICALBAR", SDL_SCANCODE_KP_DBLVERTICALBAR },
{ "KP_COLON", SDL_SCANCODE_KP_COLON },
{ "KP_HASH", SDL_SCANCODE_KP_HASH },
{ "KP_SPACE", SDL_SCANCODE_KP_SPACE },
{ "KP_AT", SDL_SCANCODE_KP_AT },
{ "KP_EXCLAM", SDL_SCANCODE_KP_EXCLAM },
{ "KP_MEMSTORE", SDL_SCANCODE_KP_MEMSTORE },
{ "KP_MEMRECALL", SDL_SCANCODE_KP_MEMRECALL },
{ "KP_MEMCLEAR", SDL_SCANCODE_KP_MEMCLEAR },
{ "KP_MEMADD", SDL_SCANCODE_KP_MEMADD },
{ "KP_MEMSUBTRACT", SDL_SCANCODE_KP_MEMSUBTRACT },
{ "KP_MEMMULTIPLY", SDL_SCANCODE_KP_MEMMULTIPLY },
{ "KP_MEMDIVIDE", SDL_SCANCODE_KP_MEMDIVIDE },
{ "KP_PLUSMINUS", SDL_SCANCODE_KP_PLUSMINUS },
{ "KP_CLEAR", SDL_SCANCODE_KP_CLEAR },
{ "KP_CLEARENTRY", SDL_SCANCODE_KP_CLEARENTRY },
{ "KP_BINARY", SDL_SCANCODE_KP_BINARY },
{ "KP_OCTAL", SDL_SCANCODE_KP_OCTAL },
{ "KP_DECIMAL", SDL_SCANCODE_KP_DECIMAL },
{ "KP_HEXADECIMAL", SDL_SCANCODE_KP_HEXADECIMAL },
{ "LCTRL", SDL_SCANCODE_LCTRL },
{ "LSHIFT", SDL_SCANCODE_LSHIFT },
{ "LALT", SDL_SCANCODE_LALT },
{ "LGUI", SDL_SCANCODE_LGUI },
{ "RCTRL", SDL_SCANCODE_RCTRL },
{ "RSHIFT", SDL_SCANCODE_RSHIFT },
{ "RALT", SDL_SCANCODE_RALT },
{ "RGUI", SDL_SCANCODE_RGUI },
{ "CLEAR AGAIN", SDL_SCANCODE_CLEARAGAIN },
{ "CR SEL", SDL_SCANCODE_CRSEL },
{ "EX SEL", SDL_SCANCODE_EXSEL },
{ "KP 00", SDL_SCANCODE_KP_00 },
{ "KP 000", SDL_SCANCODE_KP_000 },
{ "THOUSANDS SEPARATOR", SDL_SCANCODE_THOUSANDSSEPARATOR },
{ "DECIMAL SEPARATOR", SDL_SCANCODE_DECIMALSEPARATOR },
{ "CURRENCY UNIT", SDL_SCANCODE_CURRENCYUNIT },
{ "CURRENCY SUBUNIT", SDL_SCANCODE_CURRENCYSUBUNIT },
{ "KP LEFT PAREN", SDL_SCANCODE_KP_LEFTPAREN },
{ "KP RIGHT PAREN", SDL_SCANCODE_KP_RIGHTPAREN },
{ "KP LEFT BRACE", SDL_SCANCODE_KP_LEFTBRACE },
{ "KP RIGHT BRACE", SDL_SCANCODE_KP_RIGHTBRACE },
{ "KP TAB", SDL_SCANCODE_KP_TAB },
{ "KP BACKSPACE", SDL_SCANCODE_KP_BACKSPACE },
{ "KP A", SDL_SCANCODE_KP_A },
{ "KP B", SDL_SCANCODE_KP_B },
{ "KP C", SDL_SCANCODE_KP_C },
{ "KP D", SDL_SCANCODE_KP_D },
{ "KP E", SDL_SCANCODE_KP_E },
{ "KP F", SDL_SCANCODE_KP_F },
{ "KP XOR", SDL_SCANCODE_KP_XOR },
{ "KP POWER", SDL_SCANCODE_KP_POWER },
{ "KP PERCENT", SDL_SCANCODE_KP_PERCENT },
{ "KP LESS", SDL_SCANCODE_KP_LESS },
{ "KP GREATER", SDL_SCANCODE_KP_GREATER },
{ "KP AMPERSAND", SDL_SCANCODE_KP_AMPERSAND },
{ "KP DBL AMPERSAND", SDL_SCANCODE_KP_DBLAMPERSAND },
{ "KP VERTICAL BAR", SDL_SCANCODE_KP_VERTICALBAR },
{ "KP DBL VERTICAL BAR", SDL_SCANCODE_KP_DBLVERTICALBAR },
{ "KP COLON", SDL_SCANCODE_KP_COLON },
{ "KP HASH", SDL_SCANCODE_KP_HASH },
{ "KP SPACE", SDL_SCANCODE_KP_SPACE },
{ "KP AT", SDL_SCANCODE_KP_AT },
{ "KP EXCLAM", SDL_SCANCODE_KP_EXCLAM },
{ "KP MEM STORE", SDL_SCANCODE_KP_MEMSTORE },
{ "KP MEM RECALL", SDL_SCANCODE_KP_MEMRECALL },
{ "KP MEM CLEAR", SDL_SCANCODE_KP_MEMCLEAR },
{ "KP MEM ADD", SDL_SCANCODE_KP_MEMADD },
{ "KP MEM SUBTRACT", SDL_SCANCODE_KP_MEMSUBTRACT },
{ "KP MEM MULTIPLY", SDL_SCANCODE_KP_MEMMULTIPLY },
{ "KP MEM DIVIDE", SDL_SCANCODE_KP_MEMDIVIDE },
{ "KP PLUS/MINUS", SDL_SCANCODE_KP_PLUSMINUS },
{ "KP CLEAR", SDL_SCANCODE_KP_CLEAR },
{ "KP CLEAR ENTRY", SDL_SCANCODE_KP_CLEARENTRY },
{ "KP BINARY", SDL_SCANCODE_KP_BINARY },
{ "KP OCTAL", SDL_SCANCODE_KP_OCTAL },
{ "KP DECIMAL", SDL_SCANCODE_KP_DECIMAL },
{ "KP HEXADECIMAL", SDL_SCANCODE_KP_HEXADECIMAL },
{ "LEFT CTRL", SDL_SCANCODE_LCTRL },
{ "LEFT SHIFT", SDL_SCANCODE_LSHIFT },
{ "LEFT ALT", SDL_SCANCODE_LALT },
{ "LEFT SUPER", SDL_SCANCODE_LGUI },
{ "RIGHT CTRL", SDL_SCANCODE_RCTRL },
{ "RIGHT SHIFT", SDL_SCANCODE_RSHIFT },
{ "RIGHT ALT", SDL_SCANCODE_RALT },
{ "RIGHT SUPER", SDL_SCANCODE_RGUI },
{ "MODE", SDL_SCANCODE_MODE },
{ "AUDIONEXT", SDL_SCANCODE_AUDIONEXT },
{ "AUDIOPREV", SDL_SCANCODE_AUDIOPREV },
{ "AUDIOSTOP", SDL_SCANCODE_AUDIOSTOP },
{ "AUDIOPLAY", SDL_SCANCODE_AUDIOPLAY },
{ "AUDIOMUTE", SDL_SCANCODE_AUDIOMUTE },
{ "MEDIASELECT", SDL_SCANCODE_MEDIASELECT },
{ "AUDIO NEXT", SDL_SCANCODE_AUDIONEXT },
{ "AUDIO PREV", SDL_SCANCODE_AUDIOPREV },
{ "AUDIO STOP", SDL_SCANCODE_AUDIOSTOP },
{ "AUDIO PLAY", SDL_SCANCODE_AUDIOPLAY },
{ "AUDIO MUTE", SDL_SCANCODE_AUDIOMUTE },
{ "MEDIA SELECT", SDL_SCANCODE_MEDIASELECT },
{ "WWW", SDL_SCANCODE_WWW },
{ "MAIL", SDL_SCANCODE_MAIL },
{ "CALCULATOR", SDL_SCANCODE_CALCULATOR },
{ "COMPUTER", SDL_SCANCODE_COMPUTER },
{ "AC_SEARCH", SDL_SCANCODE_AC_SEARCH },
{ "AC_HOME", SDL_SCANCODE_AC_HOME },
{ "AC_BACK", SDL_SCANCODE_AC_BACK },
{ "AC_FORWARD", SDL_SCANCODE_AC_FORWARD },
{ "AC_STOP", SDL_SCANCODE_AC_STOP },
{ "AC_REFRESH", SDL_SCANCODE_AC_REFRESH },
{ "AC_BOOKMARKS", SDL_SCANCODE_AC_BOOKMARKS },
{ "BRIGHTNESSDOWN", SDL_SCANCODE_BRIGHTNESSDOWN },
{ "BRIGHTNESSUP", SDL_SCANCODE_BRIGHTNESSUP },
{ "DISPLAYSWITCH", SDL_SCANCODE_DISPLAYSWITCH },
{ "KBDILLUMTOGGLE", SDL_SCANCODE_KBDILLUMTOGGLE },
{ "KBDILLUMDOWN", SDL_SCANCODE_KBDILLUMDOWN },
{ "KBDILLUMUP", SDL_SCANCODE_KBDILLUMUP },
{ "AC SEARCH", SDL_SCANCODE_AC_SEARCH },
{ "AC HOME", SDL_SCANCODE_AC_HOME },
{ "AC BACK", SDL_SCANCODE_AC_BACK },
{ "AC FORWARD", SDL_SCANCODE_AC_FORWARD },
{ "AC STOP", SDL_SCANCODE_AC_STOP },
{ "AC REFRESH", SDL_SCANCODE_AC_REFRESH },
{ "AC BOOKMARKS", SDL_SCANCODE_AC_BOOKMARKS },
{ "BRIGHTNESS DOWN", SDL_SCANCODE_BRIGHTNESSDOWN },
{ "BRIGHTNESS UP", SDL_SCANCODE_BRIGHTNESSUP },
{ "DISPLAY SWITCH", SDL_SCANCODE_DISPLAYSWITCH },
{ "KBD ILLUM TOGGLE", SDL_SCANCODE_KBDILLUMTOGGLE },
{ "KBD ILLUM DOWN", SDL_SCANCODE_KBDILLUMDOWN },
{ "KBD ILLUM UP", SDL_SCANCODE_KBDILLUMUP },
{ "EJECT", SDL_SCANCODE_EJECT },
{ "SLEEP", SDL_SCANCODE_SLEEP },
{ "APP1", SDL_SCANCODE_APP1 },
{ "APP2", SDL_SCANCODE_APP2 },
{ "AUDIOREWIND", SDL_SCANCODE_AUDIOREWIND },
{ "AUDIOFASTFORWARD", SDL_SCANCODE_AUDIOFASTFORWARD },
{ "SOFTLEFT", SDL_SCANCODE_SOFTLEFT },
{ "SOFTRIGHT", SDL_SCANCODE_SOFTRIGHT },
{ "APP 1", SDL_SCANCODE_APP1 },
{ "APP 2", SDL_SCANCODE_APP2 },
{ "AUDIO REWIND", SDL_SCANCODE_AUDIOREWIND },
{ "AUDIO FAST FORWARD", SDL_SCANCODE_AUDIOFASTFORWARD },
{ "SOFT LEFT", SDL_SCANCODE_SOFTLEFT },
{ "SOFT RIGHT", SDL_SCANCODE_SOFTRIGHT },
{ "CALL", SDL_SCANCODE_CALL },
{ "ENDCALL", SDL_SCANCODE_ENDCALL },
{ "END CALL", SDL_SCANCODE_ENDCALL },
};
CONFIG_DEFINE_ENUM_TEMPLATE(EChannelConfiguration)
-6
View File
@@ -1,12 +1,6 @@
#include "registry.h"
#include <os/process.h>
#include <os/registry.h>
#include <user/config.h>
void Registry::Load()
{
}
void Registry::Save()
{
-1
View File
@@ -3,6 +3,5 @@
class Registry
{
public:
static void Load();
static void Save();
};
+22
View File
@@ -914,3 +914,25 @@ jump_address = 0x82AE2774
name = "ApplicationFrameLimiterMidAsmHook"
address = 0x822C1064
jump_address = 0x822C111C
[[midasm_hook]]
name = "PressStartSaveLoadThreadMidAsmHook"
address = 0x822C4358
[[midasm_hook]]
name = "FxShadowMapInitMidAsmHook"
address = 0x82BAD8F4
registers = ["r11"]
[[midasm_hook]]
name = "FxShadowMapNoTerrainMidAsmHook"
address = 0x82BAD9EC
registers = ["r4", "r30"]
after_instruction = true
[[midasm_hook]]
name = "FxShadowMapMidAsmHook"
address = 0x82BADADC
registers = ["r4", "r5", "r6", "r30"]
jump_address_on_true = 0x82BAD9F0
jump_address_on_false = 0x82BADAFC