mirror of
https://github.com/sal063/AC6_recomp
synced 2026-07-08 14:36:57 -04:00
Fix AC6 >1x mosaic and cloud/effects de-swizzle streaks
Upscale mosaic. At draw-resolution scale > 1, AC6's deferred EDRAM restore passes do integer pixel-address math on the PsParamGen position. Its leftover sub-guest-pixel fraction scrambles into an 8x8 mosaic. Floor the param-gen position (param_gen_integer_guest_position) and re-add the host sub-pixel at the fetch (param_gen_host_subpixel_restore). Inert at 1x. De-swizzle scramble. Some AC6 restore/resample passes manually de-swizzle the Xenos EDRAM sub-tile layout of their source, which is only correct on tiled data. The emulator detiles everything to linear, so the de-swizzle always scrambles, streaking the cloud/effects pipeline. For allowlisted shader hashes (ac6_neutralize_deswizzle_hashes) the sample coordinate is replaced with the identity host-texel UV (a 1:1 copy).
This commit is contained in:
@@ -17,6 +17,9 @@ REXCVAR_DECLARE(bool, direct_host_resolve);
|
||||
REXCVAR_DECLARE(int32_t, resolution_scale);
|
||||
REXCVAR_DECLARE(int32_t, draw_resolution_scale_x);
|
||||
REXCVAR_DECLARE(int32_t, draw_resolution_scale_y);
|
||||
REXCVAR_DECLARE(bool, param_gen_integer_guest_position);
|
||||
REXCVAR_DECLARE(bool, param_gen_host_subpixel_restore);
|
||||
REXCVAR_DECLARE(std::string, ac6_neutralize_deswizzle_hashes);
|
||||
REXCVAR_DECLARE(std::string, log_file);
|
||||
REXCVAR_DECLARE(std::string, log_level);
|
||||
REXCVAR_DECLARE(bool, ac6_d3d_trace);
|
||||
@@ -54,6 +57,19 @@ REXCVAR_DEFINE_STRING(ac6_graphics_backend, AC6_DEFAULT_GRAPHICS_BACKEND,
|
||||
REXCVAR_DEFINE_BOOL(ac6_performance_mode, true, "AC6/Performance",
|
||||
"Disable all diagnostics, logging, and development overlays for maximum runtime performance");
|
||||
|
||||
// Correctness-fix switches. Each expands
|
||||
// to its detailed cvars + AC6-specific shader hashes in ApplyAc6FixDefaults()
|
||||
// unless the user overrode them.
|
||||
REXCVAR_DEFINE_BOOL(ac6_fix_scaling, true, "AC6",
|
||||
"Fix the upscaling mosaic on AC6's deferred EDRAM restore passes by "
|
||||
"flooring the PsParamGen pixel position (+ host sub-pixel restore). "
|
||||
"Auto-applies only at draw resolution scale > 1; inert at 1x. On by default.");
|
||||
REXCVAR_DEFINE_BOOL(ac6_fix_deswizzle, true, "AC6",
|
||||
"Fix the de-swizzle mosaic/streaks: identity-override AC6's manual EDRAM "
|
||||
"sub-tile de-swizzle, which is always a wrong texel permutation once the "
|
||||
"emulator detiles to linear. On by default; effective at all draw scales "
|
||||
"(the swizzle is present at 1x too).");
|
||||
|
||||
#include "generated/ac6recomp_config.h"
|
||||
#include "generated/ac6recomp_init.h"
|
||||
|
||||
@@ -82,6 +98,8 @@ void ApplyAc6HybridStartupSafetyOverrides() {
|
||||
REXCVAR_SET(draw_resolution_scale_x, 1);
|
||||
REXCVAR_SET(draw_resolution_scale_y, 1);
|
||||
}
|
||||
// (The >1x param-gen mosaic fix is applied by ApplyAc6FixDefaults via
|
||||
// ac6_fix_scaling.)
|
||||
|
||||
if (REXCVAR_GET(ac6_force_safe_direct_host_resolve)) {
|
||||
REXCVAR_SET(direct_host_resolve, false);
|
||||
@@ -139,6 +157,32 @@ void ApplyAc6PerformanceModeOverrides() {
|
||||
REXCVAR_SET(ac6_texture_swaps_dump_enabled, false);
|
||||
}
|
||||
|
||||
// Each fix switch -> its detailed cvars + AC6-specific shader hashes. The
|
||||
// game-specific constants live here in code, not in the user's toml; each
|
||||
// value is filled in only if the user did NOT set it explicitly, so any toml
|
||||
// override still wins (the dev/debug path).
|
||||
#define AC6_SET_IF_UNSET(cv, value) \
|
||||
do { if (!rex::cvar::HasNonDefaultValue(#cv)) REXCVAR_SET(cv, value); } while (0)
|
||||
|
||||
void ApplyAc6FixDefaults() {
|
||||
const bool scaled = REXCVAR_GET(draw_resolution_scale_x) > 1 ||
|
||||
REXCVAR_GET(draw_resolution_scale_y) > 1;
|
||||
|
||||
// param_gen floor + host sub-pixel restore only bites at >1x --
|
||||
// inert at 1x, so gate it on the draw scale.
|
||||
if (REXCVAR_GET(ac6_fix_scaling) && scaled) {
|
||||
AC6_SET_IF_UNSET(param_gen_integer_guest_position, true);
|
||||
AC6_SET_IF_UNSET(param_gen_host_subpixel_restore, true);
|
||||
}
|
||||
// de-swizzle identity override is a texture-layout mismatch present
|
||||
// at ALL draw scales, so it is NOT gated on scale.
|
||||
if (REXCVAR_GET(ac6_fix_deswizzle)) {
|
||||
AC6_SET_IF_UNSET(ac6_neutralize_deswizzle_hashes,
|
||||
"7d22894002d16018, 17e5e4ac3e713245:4");
|
||||
}
|
||||
}
|
||||
#undef AC6_SET_IF_UNSET
|
||||
|
||||
} // namespace
|
||||
|
||||
void ApplyAc6PerformanceModeOverridesPublic() {
|
||||
@@ -169,6 +213,7 @@ std::unique_ptr<rex::ui::WindowedApp> Ac6recompAppCreate(rex::ui::WindowedAppCon
|
||||
REXCVAR_SET(ac6_unlock_fps, false);
|
||||
ApplyAc6DefaultSettings();
|
||||
ApplyAc6HybridStartupSafetyOverrides();
|
||||
ApplyAc6FixDefaults();
|
||||
ApplyAc6PerformanceModeOverrides();
|
||||
|
||||
REXLOG_INFO("Ac6recompAppCreate: graphics mode={} capture={}",
|
||||
|
||||
@@ -29,6 +29,9 @@ REXCVAR_DECLARE(int32_t, draw_resolution_scale_x);
|
||||
REXCVAR_DECLARE(int32_t, draw_resolution_scale_y);
|
||||
REXCVAR_DECLARE(bool, resolve_resolution_scale_fill_half_pixel_offset);
|
||||
REXCVAR_DECLARE(bool, draw_resolution_scaled_texture_offsets);
|
||||
REXCVAR_DECLARE(bool, param_gen_integer_guest_position);
|
||||
REXCVAR_DECLARE(bool, param_gen_host_subpixel_restore);
|
||||
REXCVAR_DECLARE(std::string, ac6_neutralize_deswizzle_hashes);
|
||||
REXCVAR_DECLARE(std::string, readback_resolve);
|
||||
REXCVAR_DECLARE(bool, readback_resolve_half_pixel_offset);
|
||||
REXCVAR_DECLARE(bool, readback_memexport);
|
||||
|
||||
+32
@@ -33,6 +33,38 @@ REXCVAR_DEFINE_BOOL(vfetch_index_rounding_bias, false, "GPU/Shader",
|
||||
"flooring to fix black triangles caused by RCP precision");
|
||||
REXCVAR_DEFINE_BOOL(draw_resolution_scaled_texture_offsets, true, "GPU/Shader",
|
||||
"Scale texture offsets with draw resolution");
|
||||
REXCVAR_DEFINE_BOOL(param_gen_integer_guest_position, false, "GPU/Shader",
|
||||
"At >1x draw resolution scale, floor the PsParamGen pixel "
|
||||
"position to the integer guest-pixel index instead of keeping "
|
||||
"the sub-guest-pixel fraction. Fixes the mosaic in games that "
|
||||
"feed the position into their own integer pixel-address math "
|
||||
"(e.g. AC6's deferred EDRAM restore/de-swizzle passes), whose "
|
||||
"frac()-based bit extraction otherwise sees a doubled period and "
|
||||
"scrambles the sample coordinate. Those passes then sample at "
|
||||
"guest resolution. Off by default; harmless for shaders that pass "
|
||||
"the position straight to tfetch only at 1x.");
|
||||
REXCVAR_DEFINE_BOOL(param_gen_host_subpixel_restore, false, "GPU/Shader",
|
||||
"Builds on param_gen_integer_guest_position (and implies it): for "
|
||||
"resolution-scaled, position-derived 2D samples in pixel shaders "
|
||||
"that use PsParamGen, re-adds the host sub-pixel offset to the "
|
||||
"sample coordinate so the de-swizzle restore passes sample at full "
|
||||
"host resolution instead of the guest-texel center. Turns the "
|
||||
"mosaic fix from clean-but-soft into true resolution-scaled detail. "
|
||||
"Off by default; may need per-shader scoping if it disturbs other "
|
||||
"passes that read scaled render targets via interpolated coords.");
|
||||
REXCVAR_DEFINE_STRING(ac6_neutralize_deswizzle_hashes, "", "GPU/Shader",
|
||||
"AC6: comma/space-separated tokens \"<hash>[:<slot>[+<slot>...]]\" "
|
||||
"naming guest pixel-shader ucode hashes (hex) whose param_gen 2D "
|
||||
"texture samples manually de-swizzle the raw EDRAM sub-tile order of "
|
||||
"their source. The emulator's texture cache detiles everything to "
|
||||
"linear, so that de-swizzle is always a wrong texel permutation here "
|
||||
"(the mosaic/streak class). For a matching fetch the sample "
|
||||
"coordinate is replaced unconditionally with the identity host-texel "
|
||||
"UV (SV_Position.xy / (guest_size * scale)) -- a 1:1 copy. A bare "
|
||||
"hash overrides ALL of that shader's fetches; \":4\" limits it to "
|
||||
"Xenos tfetch slot 4 (needed when only some fetches de-swizzle, e.g. "
|
||||
"the AC6 cloud compositor: scene fetch de-swizzles, mask/cloud "
|
||||
"fetches use plain UVs and must be left alone). Runtime, no rebuild.");
|
||||
REXCVAR_DEFINE_BOOL(gpu_debug_markers, false, "GPU",
|
||||
"Insert debug markers into GPU command streams for tools "
|
||||
"like PIX and RenderDoc. Automatically enabled when "
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#include <rex/assert.h>
|
||||
#include <rex/cvar.h>
|
||||
#include <rex/logging.h>
|
||||
#include <rex/graphics/pipeline/shader/dxbc.h>
|
||||
#include <rex/graphics/pipeline/shader/dxbc_translator.h>
|
||||
#include <rex/graphics/xenos.h>
|
||||
@@ -28,6 +29,10 @@ REXCVAR_DEFINE_BOOL(dxbc_switch, true, "GPU/Shader", "Use switch statements in D
|
||||
|
||||
REXCVAR_DEFINE_BOOL(dxbc_source_map, false, "GPU/Shader", "Generate source maps for DXBC");
|
||||
|
||||
// Defined in graphics/flags.cpp; read by param_gen below.
|
||||
REXCVAR_DECLARE(bool, param_gen_integer_guest_position);
|
||||
REXCVAR_DECLARE(bool, param_gen_host_subpixel_restore);
|
||||
|
||||
namespace rex::graphics {
|
||||
using namespace ucode;
|
||||
|
||||
@@ -668,6 +673,22 @@ void DxbcShaderTranslator::StartPixelShader() {
|
||||
a_.OpMul(dxbc::Dest::R(param_gen_temp, resolution_scaled_axes), dxbc::Src::R(param_gen_temp),
|
||||
dxbc::Src::LF(1.0f / draw_resolution_scale_x_, 1.0f / draw_resolution_scale_y_, 1.0f,
|
||||
1.0f));
|
||||
if (REXCVAR_GET(param_gen_integer_guest_position) ||
|
||||
REXCVAR_GET(param_gen_host_subpixel_restore)) {
|
||||
// Snap the reverted position to the integer guest-pixel index. The
|
||||
// multiply above leaves a sub-guest-pixel fraction (e.g. .5 at 2x) which
|
||||
// is correct only for shaders that feed PsParamGen straight to tfetch.
|
||||
// (param_gen_host_subpixel_restore re-adds that sub-pixel later, at the
|
||||
// texture fetch, so the restore passes regain full host resolution.)
|
||||
// Games that instead do integer pixel-address math on the position (AC6's
|
||||
// deferred EDRAM restore/de-swizzle passes) break, because their
|
||||
// frac()-based bit extraction sees a doubled period at >1x and scrambles
|
||||
// the sample coordinate into an 8x8 mosaic. Flooring here makes that math
|
||||
// operate on integer guest pixels again, at the cost of those passes
|
||||
// sampling at guest resolution.
|
||||
a_.OpRoundNI(dxbc::Dest::R(param_gen_temp, resolution_scaled_axes),
|
||||
dxbc::Src::R(param_gen_temp));
|
||||
}
|
||||
}
|
||||
if (shader_modification.pixel.param_gen_point) {
|
||||
// A point - always front-facing (the upper bit of X is 0), not a line
|
||||
|
||||
+156
@@ -11,6 +11,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
|
||||
@@ -27,6 +28,57 @@
|
||||
namespace rex::graphics {
|
||||
using namespace ucode;
|
||||
|
||||
namespace {
|
||||
// Returns true if `hash` + `tfetch_index` is allowlisted by `list`, a string of
|
||||
// tokens separated by commas/spaces/semicolons. Each token is
|
||||
// "<hex-hash>[:<slot>[+<slot>...]]" (optional "0x" prefix on the hash):
|
||||
// a bare hash matches ALL of that shader's fetch slots; with ":4" or ":1+2"
|
||||
// only the listed Xenos tfetch slots match. Used to allowlist specific guest
|
||||
// pixel shaders (and optionally specific fetches within them, e.g. only the
|
||||
// de-swizzled fetch of a compositor whose other fetches use plain UVs) at
|
||||
// runtime, so re-targeting needs no rebuild.
|
||||
bool UcodeHashSlotInList(uint64_t hash, uint32_t tfetch_index, const std::string& list) {
|
||||
auto is_sep = [](char c) {
|
||||
return c == ',' || c == ';' || c == ' ' || c == '\t' || c == '\n' || c == '\r';
|
||||
};
|
||||
size_t i = 0, n = list.size();
|
||||
while (i < n) {
|
||||
while (i < n && is_sep(list[i])) {
|
||||
++i;
|
||||
}
|
||||
size_t start = i;
|
||||
while (i < n && !is_sep(list[i])) {
|
||||
++i;
|
||||
}
|
||||
if (i > start) {
|
||||
std::string token = list.substr(start, i - start);
|
||||
size_t colon = token.find(':');
|
||||
std::string hash_part = colon == std::string::npos ? token : token.substr(0, colon);
|
||||
if (std::strtoull(hash_part.c_str(), nullptr, 16) == hash) {
|
||||
if (colon == std::string::npos) {
|
||||
return true; // No slot list - all slots.
|
||||
}
|
||||
size_t p = colon + 1;
|
||||
while (p < token.size()) {
|
||||
size_t q = token.find('+', p);
|
||||
if (q == std::string::npos) {
|
||||
q = token.size();
|
||||
}
|
||||
if (q > p &&
|
||||
std::strtoul(token.substr(p, q - p).c_str(), nullptr, 10) == tfetch_index) {
|
||||
return true;
|
||||
}
|
||||
p = q + 1;
|
||||
}
|
||||
// Hash matched but this slot isn't listed - keep scanning (the same
|
||||
// hash may appear again with other slots).
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void DxbcShaderTranslator::ProcessVertexFetchInstruction(
|
||||
const ParsedVertexFetchInstruction& instr) {
|
||||
if (emit_source_map_) {
|
||||
@@ -772,6 +824,44 @@ void DxbcShaderTranslator::ProcessTextureFetchInstruction(
|
||||
// 2D, cube: X - width, Y - height (cube maps probably can be only square, but
|
||||
// for simplicity).
|
||||
// 3D: X - width, Y - height, Z - depth, W - 0 if stacked 2D, 1 if 3D.
|
||||
//
|
||||
// For resolution-scaled, position-derived 2D samples in a
|
||||
// pixel shader that uses PsParamGen (AC6's deferred restore passes), the guest
|
||||
// de-swizzle now runs on integer guest pixels (see the param_gen floor) and so
|
||||
// samples the guest-texel center, losing the host sub-pixel. We re-add it after
|
||||
// the coordinate is normalized so the sample lands on the exact host texel =
|
||||
// true resolution-scaled detail. Needs the guest texture size loaded below.
|
||||
bool apply_host_subpixel_correction =
|
||||
instr.opcode == FetchOpcode::kTextureFetch &&
|
||||
!instr.attributes.unnormalized_coordinates &&
|
||||
instr.dimension == xenos::FetchOpDimension::k2D && is_pixel_shader() &&
|
||||
GetDxbcShaderModification().pixel.param_gen_enable &&
|
||||
(draw_resolution_scale_x_ > 1 || draw_resolution_scale_y_ > 1) &&
|
||||
REXCVAR_GET(param_gen_host_subpixel_restore);
|
||||
// Surgical de-swizzle neutralize: some AC6 full-screen
|
||||
// "restore/resample" passes manually de-swizzle the Xenos sub-tile layout of
|
||||
// their source. That is correct only when the emulator keeps the source
|
||||
// already-swizzled (scaled-resolve). When the source was detiled to LINEAR,
|
||||
// the same de-swizzle scrambles it -> the streak that feeds the cloud/effects
|
||||
// pipeline. For an allowlisted shader (by
|
||||
// guest ucode hash; runtime string cvar) we replace the scrambled coordinate
|
||||
// with the identity host-texel UV = SV_Position.xy / (guest_size * scale), a
|
||||
// 1:1 copy. The layout mismatch is scale-independent -- the source is linear
|
||||
// at 1x too, so this applies at ALL draw
|
||||
// resolutions. (Only the separate param_gen sub-pixel restore above stays
|
||||
// >1x-gated, since host sub-pixel detail exists only when upscaling.)
|
||||
bool apply_deswizzle_identity = false;
|
||||
if (instr.opcode == FetchOpcode::kTextureFetch &&
|
||||
!instr.attributes.unnormalized_coordinates &&
|
||||
instr.dimension == xenos::FetchOpDimension::k2D && is_pixel_shader() &&
|
||||
GetDxbcShaderModification().pixel.param_gen_enable) {
|
||||
const std::string& neutralize_hashes =
|
||||
REXCVAR_GET(ac6_neutralize_deswizzle_hashes);
|
||||
apply_deswizzle_identity =
|
||||
!neutralize_hashes.empty() &&
|
||||
UcodeHashSlotInList(current_shader().ucode_data_hash(), tfetch_index,
|
||||
neutralize_hashes);
|
||||
}
|
||||
uint32_t size_needed_components = 0b0000;
|
||||
if (instr.opcode == FetchOpcode::kGetTextureWeights) {
|
||||
// Size needed for denormalization for coordinate lerp factor.
|
||||
@@ -836,6 +926,12 @@ void DxbcShaderTranslator::ProcessTextureFetchInstruction(
|
||||
// the texture is 3D unconditionally.
|
||||
size_needed_components |= 0b1000;
|
||||
}
|
||||
if (apply_host_subpixel_correction || apply_deswizzle_identity) {
|
||||
// Need the guest texture width/height (XY) to convert the host sub-pixel
|
||||
// offset (Tier B) or the SV_Position into normalized texture space
|
||||
// (de-swizzle identity).
|
||||
size_needed_components |= 0b0011;
|
||||
}
|
||||
uint32_t size_and_is_3d_temp = size_needed_components ? PushSystemTemp() : UINT32_MAX;
|
||||
if (size_needed_components) {
|
||||
switch (instr.dimension) {
|
||||
@@ -1147,6 +1243,66 @@ void DxbcShaderTranslator::ProcessTextureFetchInstruction(
|
||||
}
|
||||
}
|
||||
}
|
||||
if (apply_host_subpixel_correction) {
|
||||
// coord_and_sampler_temp.xy is the final normalized coordinate, sampling
|
||||
// the guest-texel center (host texel scale*swizzle(g) + scale/2). Shift it
|
||||
// to the current host sub-pixel so it samples host texel scale*swizzle(g)+s
|
||||
// (= the host-resolution swizzle), landing on an exact texel center.
|
||||
uint32_t host_subpixel_temp = PushSystemTemp();
|
||||
// host_subpixel.xy = floor(SV_Position.xy) mod draw_resolution_scale.
|
||||
in_position_used_ |= 0b0011;
|
||||
a_.OpFToU(dxbc::Dest::R(host_subpixel_temp, 0b0011),
|
||||
dxbc::Src::V1D(in_reg_ps_position_));
|
||||
a_.OpUDiv(dxbc::Dest::Null(), dxbc::Dest::R(host_subpixel_temp, 0b0011),
|
||||
dxbc::Src::R(host_subpixel_temp),
|
||||
dxbc::Src::LU(uint32_t(draw_resolution_scale_x_),
|
||||
uint32_t(draw_resolution_scale_y_), 1, 1));
|
||||
a_.OpUToF(dxbc::Dest::R(host_subpixel_temp, 0b0011), dxbc::Src::R(host_subpixel_temp));
|
||||
// delta.xy = (host_subpixel - (scale-1)/2) / (guest_size * scale).
|
||||
a_.OpAdd(dxbc::Dest::R(host_subpixel_temp, 0b0011), dxbc::Src::R(host_subpixel_temp),
|
||||
dxbc::Src::LF(-(float(draw_resolution_scale_x_) - 1.0f) * 0.5f,
|
||||
-(float(draw_resolution_scale_y_) - 1.0f) * 0.5f, 0.0f, 0.0f));
|
||||
a_.OpDiv(dxbc::Dest::R(host_subpixel_temp, 0b0011), dxbc::Src::R(host_subpixel_temp),
|
||||
dxbc::Src::R(size_and_is_3d_temp));
|
||||
a_.OpMul(dxbc::Dest::R(host_subpixel_temp, 0b0011), dxbc::Src::R(host_subpixel_temp),
|
||||
dxbc::Src::LF(1.0f / float(draw_resolution_scale_x_),
|
||||
1.0f / float(draw_resolution_scale_y_), 0.0f, 0.0f));
|
||||
// Only resolution-scaled textures are stored at host resolution.
|
||||
a_.OpAnd(dxbc::Dest::R(host_subpixel_temp, 0b0100),
|
||||
LoadSystemConstant(SystemConstants::Index::kTexturesResolutionScaled,
|
||||
offsetof(SystemConstants, textures_resolution_scaled),
|
||||
dxbc::Src::kXXXX),
|
||||
dxbc::Src::LU(uint32_t(1) << tfetch_index));
|
||||
a_.OpIf(true, dxbc::Src::R(host_subpixel_temp, dxbc::Src::kZZZZ));
|
||||
a_.OpAdd(dxbc::Dest::R(coord_and_sampler_temp, 0b0011),
|
||||
dxbc::Src::R(coord_and_sampler_temp), dxbc::Src::R(host_subpixel_temp));
|
||||
a_.OpEndIf();
|
||||
// Release host_subpixel_temp.
|
||||
PopSystemTemp();
|
||||
}
|
||||
if (apply_deswizzle_identity) {
|
||||
// coord_and_sampler_temp.xy is the guest de-swizzled coordinate. The guest
|
||||
// wrote these restore/resample passes for raw EDRAM-ordered resolve data,
|
||||
// but the emulator's texture cache detiles EVERYTHING to linear,
|
||||
// so the de-swizzle is always a wrong texel
|
||||
// permutation here.
|
||||
// Replace it with the identity host-texel UV =
|
||||
// SV_Position.xy / (guest_size * scale) so the pass copies its source 1:1.
|
||||
// Unconditional within allowlisted shaders: there is no swizzled-content
|
||||
// texture this could break.
|
||||
uint32_t deswizzle_temp = PushSystemTemp();
|
||||
in_position_used_ |= 0b0011;
|
||||
// deswizzle_temp.xy = guest_size * draw_resolution_scale = host size.
|
||||
a_.OpMul(dxbc::Dest::R(deswizzle_temp, 0b0011),
|
||||
dxbc::Src::R(size_and_is_3d_temp),
|
||||
dxbc::Src::LF(float(draw_resolution_scale_x_),
|
||||
float(draw_resolution_scale_y_), 1.0f, 1.0f));
|
||||
// coord.xy = SV_Position.xy / host size = identity texel-center UV.
|
||||
a_.OpDiv(dxbc::Dest::R(coord_and_sampler_temp, 0b0011),
|
||||
dxbc::Src::V1D(in_reg_ps_position_), dxbc::Src::R(deswizzle_temp));
|
||||
// Release deswizzle_temp.
|
||||
PopSystemTemp();
|
||||
}
|
||||
switch (instr.dimension) {
|
||||
case xenos::FetchOpDimension::k1D:
|
||||
// Pad to 2D array coordinates.
|
||||
|
||||
Reference in New Issue
Block a user