Fixed a bug with readback_resolve and readback_memexport that was responsible for a large portion of their overhead. readback_memexport and resolve are now usable for games, depending on your hardware. in my case games that were slideshows now run at like 20-30 fps, and my hardware isnt the best for xenia.
add split_map class for mapping keys to values in a way that optimizes for frequent searches and infrequent insertions/removals remove jump table implementation of GetColorRenderTargetFormatComponentCount, it was appearing relatively high in profiles. instead pack the component counts into a single 32 bit word, which is indexed by shifting Add cvar to align all basic blocks to a boundary Add mmio aware load paths liberally apply XE_RESTRICT in ringbuffer related code Removed the IS_TRUE and IS_FALSE opcodes, they were pointless duplicates of COMPARE_EQ/COMPARE_NE and i want to simplify our set of opcodes for future backends More work on LVSR/LVSL/STVR/STVL opcodes Optimized X64 translated code emission, now only compute instrkey once Add code for pre-computing integer division magic numbers Optimized GetHostViewportInfo a little Move args for GetHostViewportInfo into a class, cache the result and compare for future queries. moved GetHostViewportInfo far lower on the profile Add (currently not functional, and very racy) asynchronous memcpy code. will improve it and actually use it in future commits. Add non-temporal memcpy function for huge page-aligned allocations. Used for copying to shared memory/readback hoist are_accumulated_render_targets_valid_ check out of loop in render_target_cache already bound check. Add stosb/movsb code for small constant memcpys/memsets that arent worth the overhead of memcpy/memset
This commit is contained in:
@@ -7,18 +7,17 @@
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/gpu/d3d12/d3d12_command_processor.h"
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/base/byte_order.h"
|
||||
#include "xenia/base/cvar.h"
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/base/math.h"
|
||||
#include "xenia/base/profiling.h"
|
||||
#include "xenia/gpu/d3d12/d3d12_command_processor.h"
|
||||
#include "xenia/gpu/d3d12/d3d12_graphics_system.h"
|
||||
#include "xenia/gpu/d3d12/d3d12_shader.h"
|
||||
#include "xenia/gpu/draw_util.h"
|
||||
@@ -843,6 +842,7 @@ bool D3D12CommandProcessor::SetupContext() {
|
||||
bool draw_resolution_scale_not_clamped =
|
||||
TextureCache::GetConfigDrawResolutionScale(draw_resolution_scale_x,
|
||||
draw_resolution_scale_y);
|
||||
|
||||
if (!D3D12TextureCache::ClampDrawResolutionScaleToMaxSupported(
|
||||
draw_resolution_scale_x, draw_resolution_scale_y, provider)) {
|
||||
draw_resolution_scale_not_clamped = false;
|
||||
@@ -1676,37 +1676,52 @@ void D3D12CommandProcessor::ShutdownContext() {
|
||||
|
||||
CommandProcessor::ShutdownContext();
|
||||
}
|
||||
|
||||
// todo: bit-pack the bools and use bitarith to reduce branches
|
||||
void D3D12CommandProcessor::WriteRegister(uint32_t index, uint32_t value) {
|
||||
CommandProcessor::WriteRegister(index, value);
|
||||
|
||||
if (index >= XE_GPU_REG_SHADER_CONSTANT_000_X &&
|
||||
index <= XE_GPU_REG_SHADER_CONSTANT_511_W) {
|
||||
if (frame_open_) {
|
||||
uint32_t float_constant_index =
|
||||
(index - XE_GPU_REG_SHADER_CONSTANT_000_X) >> 2;
|
||||
if (float_constant_index >= 256) {
|
||||
float_constant_index -= 256;
|
||||
if (current_float_constant_map_pixel_[float_constant_index >> 6] &
|
||||
(1ull << (float_constant_index & 63))) {
|
||||
cbuffer_binding_float_pixel_.up_to_date = false;
|
||||
}
|
||||
} else {
|
||||
if (current_float_constant_map_vertex_[float_constant_index >> 6] &
|
||||
(1ull << (float_constant_index & 63))) {
|
||||
cbuffer_binding_float_vertex_.up_to_date = false;
|
||||
bool cbuf_binding_float_pixel_utd = cbuffer_binding_float_pixel_.up_to_date;
|
||||
bool cbuf_binding_float_vertex_utd = cbuffer_binding_float_vertex_.up_to_date;
|
||||
bool cbuf_binding_bool_loop_utd = cbuffer_binding_bool_loop_.up_to_date;
|
||||
|
||||
if (index >= XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0 &&
|
||||
index <= XE_GPU_REG_SHADER_CONSTANT_FETCH_31_5) {
|
||||
cbuffer_binding_fetch_.up_to_date = false;
|
||||
// texture cache is never nullptr
|
||||
// if (texture_cache_ != nullptr) {
|
||||
texture_cache_->TextureFetchConstantWritten(
|
||||
(index - XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0) / 6);
|
||||
// }
|
||||
} else {
|
||||
if (!(cbuf_binding_float_pixel_utd | cbuf_binding_float_vertex_utd |
|
||||
cbuf_binding_bool_loop_utd)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (index >= XE_GPU_REG_SHADER_CONSTANT_000_X &&
|
||||
index <= XE_GPU_REG_SHADER_CONSTANT_511_W) {
|
||||
if (!(cbuf_binding_float_pixel_utd | cbuf_binding_float_vertex_utd)) {
|
||||
return;
|
||||
}
|
||||
if (frame_open_) {
|
||||
uint32_t float_constant_index =
|
||||
(index - XE_GPU_REG_SHADER_CONSTANT_000_X) >> 2;
|
||||
if (float_constant_index >= 256) {
|
||||
float_constant_index -= 256;
|
||||
if (current_float_constant_map_pixel_[float_constant_index >> 6] &
|
||||
(1ull << (float_constant_index & 63))) {
|
||||
cbuffer_binding_float_pixel_.up_to_date = false;
|
||||
}
|
||||
} else {
|
||||
if (current_float_constant_map_vertex_[float_constant_index >> 6] &
|
||||
(1ull << (float_constant_index & 63))) {
|
||||
cbuffer_binding_float_vertex_.up_to_date = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (index >= XE_GPU_REG_SHADER_CONSTANT_BOOL_000_031 &&
|
||||
index <= XE_GPU_REG_SHADER_CONSTANT_LOOP_31) {
|
||||
cbuffer_binding_bool_loop_.up_to_date = false;
|
||||
} else if (index >= XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0 &&
|
||||
index <= XE_GPU_REG_SHADER_CONSTANT_FETCH_31_5) {
|
||||
cbuffer_binding_fetch_.up_to_date = false;
|
||||
if (texture_cache_ != nullptr) {
|
||||
texture_cache_->TextureFetchConstantWritten(
|
||||
(index - XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0) / 6);
|
||||
} else if (index >= XE_GPU_REG_SHADER_CONSTANT_BOOL_000_031 &&
|
||||
index <= XE_GPU_REG_SHADER_CONSTANT_LOOP_31) {
|
||||
cbuffer_binding_bool_loop_.up_to_date = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2301,14 +2316,26 @@ bool D3D12CommandProcessor::IssueDraw(xenos::PrimitiveType primitive_type,
|
||||
uint32_t draw_resolution_scale_x = texture_cache_->draw_resolution_scale_x();
|
||||
uint32_t draw_resolution_scale_y = texture_cache_->draw_resolution_scale_y();
|
||||
draw_util::ViewportInfo viewport_info;
|
||||
draw_util::GetHostViewportInfo(
|
||||
regs, draw_resolution_scale_x, draw_resolution_scale_y, true,
|
||||
draw_util::GetViewportInfoArgs gviargs{};
|
||||
|
||||
gviargs.Setup(
|
||||
draw_resolution_scale_x, draw_resolution_scale_y,
|
||||
texture_cache_->draw_resolution_scale_x_divisor(),
|
||||
texture_cache_->draw_resolution_scale_y_divisor(), true,
|
||||
D3D12_VIEWPORT_BOUNDS_MAX, D3D12_VIEWPORT_BOUNDS_MAX, false,
|
||||
normalized_depth_control,
|
||||
host_render_targets_used &&
|
||||
render_target_cache_->depth_float24_convert_in_pixel_shader(),
|
||||
host_render_targets_used, pixel_shader && pixel_shader->writes_depth(),
|
||||
viewport_info);
|
||||
host_render_targets_used, pixel_shader && pixel_shader->writes_depth());
|
||||
gviargs.SetupRegisterValues(regs);
|
||||
|
||||
if (gviargs == previous_viewport_info_args_) {
|
||||
viewport_info = previous_viewport_info_;
|
||||
} else {
|
||||
draw_util::GetHostViewportInfo(&gviargs, viewport_info);
|
||||
previous_viewport_info_args_ = gviargs;
|
||||
previous_viewport_info_ = viewport_info;
|
||||
}
|
||||
draw_util::Scissor scissor;
|
||||
draw_util::GetScissor(regs, scissor);
|
||||
scissor.offset[0] *= draw_resolution_scale_x;
|
||||
@@ -2711,6 +2738,24 @@ void D3D12CommandProcessor::InitializeTrace() {
|
||||
shared_memory_->InitializeTraceCompleteDownloads();
|
||||
}
|
||||
}
|
||||
static void DmaPrefunc(dma::XeDMAJob* job) {
|
||||
D3D12_RANGE readback_range;
|
||||
readback_range.Begin = 0;
|
||||
readback_range.End = job->size;
|
||||
void* readback_mapping;
|
||||
ID3D12Resource* readback_buffer = (ID3D12Resource*)job->userdata1;
|
||||
|
||||
HRESULT mapres = readback_buffer->Map(0, &readback_range, &readback_mapping);
|
||||
xenia_assert(SUCCEEDED(mapres));
|
||||
|
||||
job->source = (uint8_t*)readback_mapping;
|
||||
}
|
||||
|
||||
static void DmaPostfunc(dma::XeDMAJob* job) {
|
||||
D3D12_RANGE readback_write_range = {};
|
||||
ID3D12Resource* readback_buffer = (ID3D12Resource*)job->userdata1;
|
||||
readback_buffer->Unmap(0, &readback_write_range);
|
||||
}
|
||||
|
||||
bool D3D12CommandProcessor::IssueCopy() {
|
||||
#if XE_UI_D3D12_FINE_GRAINED_DRAW_SCOPES
|
||||
@@ -2736,17 +2781,35 @@ bool D3D12CommandProcessor::IssueCopy() {
|
||||
readback_buffer, 0, shared_memory_buffer, written_address,
|
||||
written_length);
|
||||
if (AwaitAllQueueOperationsCompletion()) {
|
||||
#if 1
|
||||
D3D12_RANGE readback_range;
|
||||
readback_range.Begin = 0;
|
||||
readback_range.End = written_length;
|
||||
void* readback_mapping;
|
||||
if (SUCCEEDED(
|
||||
readback_buffer->Map(0, &readback_range, &readback_mapping))) {
|
||||
std::memcpy(memory_->TranslatePhysical(written_address),
|
||||
readback_mapping, written_length);
|
||||
// chrispy: this memcpy needs to be optimized as much as possible
|
||||
|
||||
auto physaddr = memory_->TranslatePhysical(written_address);
|
||||
dma::vastcpy(physaddr, (uint8_t*)readback_mapping,
|
||||
written_length);
|
||||
// XEDmaCpy(physaddr, readback_mapping, written_length);
|
||||
D3D12_RANGE readback_write_range = {};
|
||||
readback_buffer->Unmap(0, &readback_write_range);
|
||||
}
|
||||
|
||||
#else
|
||||
dma::XeDMAJob job{};
|
||||
job.destination = memory_->TranslatePhysical(written_address);
|
||||
job.size = written_length;
|
||||
job.source = nullptr;
|
||||
job.userdata1 = (void*)readback_buffer;
|
||||
job.precall = DmaPrefunc;
|
||||
job.postcall = DmaPostfunc;
|
||||
|
||||
readback_available_ = GetDMAC()->PushDMAJob(&job);
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3885,9 +3948,10 @@ bool D3D12CommandProcessor::UpdateBindings(
|
||||
if (bool_loop_constants == nullptr) {
|
||||
return false;
|
||||
}
|
||||
std::memcpy(bool_loop_constants,
|
||||
®s[XE_GPU_REG_SHADER_CONSTANT_BOOL_000_031].u32,
|
||||
kBoolLoopConstantsSize);
|
||||
xe::smallcpy_const<kBoolLoopConstantsSize>(
|
||||
bool_loop_constants,
|
||||
®s[XE_GPU_REG_SHADER_CONSTANT_BOOL_000_031].u32);
|
||||
|
||||
cbuffer_binding_bool_loop_.up_to_date = true;
|
||||
current_graphics_root_up_to_date_ &=
|
||||
~(1u << root_parameter_bool_loop_constants);
|
||||
@@ -3901,9 +3965,9 @@ bool D3D12CommandProcessor::UpdateBindings(
|
||||
if (fetch_constants == nullptr) {
|
||||
return false;
|
||||
}
|
||||
std::memcpy(fetch_constants,
|
||||
®s[XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0].u32,
|
||||
kFetchConstantsSize);
|
||||
xe::smallcpy_const<kFetchConstantsSize>(
|
||||
fetch_constants, ®s[XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0].u32);
|
||||
|
||||
cbuffer_binding_fetch_.up_to_date = true;
|
||||
current_graphics_root_up_to_date_ &=
|
||||
~(1u << root_parameter_fetch_constants);
|
||||
@@ -4542,6 +4606,12 @@ ID3D12Resource* D3D12CommandProcessor::RequestReadbackBuffer(uint32_t size) {
|
||||
if (size == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
#if 0
|
||||
if (readback_available_) {
|
||||
GetDMAC()->WaitJobDone(readback_available_);
|
||||
readback_available_ = 0;
|
||||
}
|
||||
#endif
|
||||
size = xe::align(size, kReadbackBufferSizeIncrement);
|
||||
if (size > readback_buffer_size_) {
|
||||
const ui::d3d12::D3D12Provider& provider = GetD3D12Provider();
|
||||
@@ -4561,6 +4631,7 @@ ID3D12Resource* D3D12CommandProcessor::RequestReadbackBuffer(uint32_t size) {
|
||||
readback_buffer_->Release();
|
||||
}
|
||||
readback_buffer_ = buffer;
|
||||
readback_buffer_size_ = size;
|
||||
}
|
||||
return readback_buffer_;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/**
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
@@ -19,6 +20,7 @@
|
||||
#include <utility>
|
||||
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/base/dma.h"
|
||||
#include "xenia/gpu/command_processor.h"
|
||||
#include "xenia/gpu/d3d12/d3d12_graphics_system.h"
|
||||
#include "xenia/gpu/d3d12/d3d12_primitive_processor.h"
|
||||
@@ -581,6 +583,7 @@ class D3D12CommandProcessor final : public CommandProcessor {
|
||||
|
||||
static constexpr uint32_t kReadbackBufferSizeIncrement = 16 * 1024 * 1024;
|
||||
ID3D12Resource* readback_buffer_ = nullptr;
|
||||
dma::DMACJobHandle readback_available_ = 0;
|
||||
uint32_t readback_buffer_size_ = 0;
|
||||
|
||||
std::atomic<bool> pix_capture_requested_ = false;
|
||||
@@ -614,9 +617,11 @@ class D3D12CommandProcessor final : public CommandProcessor {
|
||||
DxbcShaderTranslator::SystemConstants system_constants_;
|
||||
|
||||
// Float constant usage masks of the last draw call.
|
||||
uint64_t current_float_constant_map_vertex_[4];
|
||||
uint64_t current_float_constant_map_pixel_[4];
|
||||
|
||||
// chrispy: make sure accesses to these cant cross cacheline boundaries
|
||||
struct alignas(XE_HOST_CACHE_LINE_SIZE) {
|
||||
uint64_t current_float_constant_map_vertex_[4];
|
||||
uint64_t current_float_constant_map_pixel_[4];
|
||||
};
|
||||
// Constant buffer bindings.
|
||||
struct ConstantBufferBinding {
|
||||
D3D12_GPU_VIRTUAL_ADDRESS address;
|
||||
@@ -670,6 +675,9 @@ class D3D12CommandProcessor final : public CommandProcessor {
|
||||
|
||||
// Current primitive topology.
|
||||
D3D_PRIMITIVE_TOPOLOGY primitive_topology_;
|
||||
|
||||
draw_util::GetViewportInfoArgs previous_viewport_info_args_;
|
||||
draw_util::ViewportInfo previous_viewport_info_;
|
||||
};
|
||||
|
||||
} // namespace d3d12
|
||||
|
||||
@@ -167,17 +167,17 @@ bool IsPixelShaderNeededWithRasterization(const Shader& shader,
|
||||
return false;
|
||||
}
|
||||
|
||||
void GetHostViewportInfo(const RegisterFile& regs,
|
||||
uint32_t draw_resolution_scale_x,
|
||||
uint32_t draw_resolution_scale_y,
|
||||
bool origin_bottom_left, uint32_t x_max,
|
||||
uint32_t y_max, bool allow_reverse_z,
|
||||
reg::RB_DEPTHCONTROL normalized_depth_control,
|
||||
bool convert_z_to_float24, bool full_float24_in_0_to_1,
|
||||
bool pixel_shader_writes_depth,
|
||||
static float ViewportRecip2_0(float f) {
|
||||
float f1 = ArchReciprocalRefined(f);
|
||||
return f1 + f1;
|
||||
}
|
||||
|
||||
// chrispy: todo, the int/float divides and the nan-checked mins show up
|
||||
// relatively high on uprof when i uc to 1.7ghz
|
||||
void GetHostViewportInfo(GetViewportInfoArgs* XE_RESTRICT args,
|
||||
ViewportInfo& viewport_info_out) {
|
||||
assert_not_zero(draw_resolution_scale_x);
|
||||
assert_not_zero(draw_resolution_scale_y);
|
||||
assert_not_zero(args->draw_resolution_scale_x);
|
||||
assert_not_zero(args->draw_resolution_scale_y);
|
||||
|
||||
// A vertex position goes the following path:
|
||||
//
|
||||
@@ -304,38 +304,32 @@ void GetHostViewportInfo(const RegisterFile& regs,
|
||||
// TODO(Triang3l): Investigate the need for clamping of oDepth to 0...1 for
|
||||
// D24FS8 as well.
|
||||
|
||||
auto pa_cl_clip_cntl = regs.Get<reg::PA_CL_CLIP_CNTL>();
|
||||
auto pa_cl_vte_cntl = regs.Get<reg::PA_CL_VTE_CNTL>();
|
||||
auto pa_su_sc_mode_cntl = regs.Get<reg::PA_SU_SC_MODE_CNTL>();
|
||||
auto pa_su_vtx_cntl = regs.Get<reg::PA_SU_VTX_CNTL>();
|
||||
auto pa_cl_clip_cntl = args->pa_cl_clip_cntl;
|
||||
auto pa_cl_vte_cntl = args->pa_cl_vte_cntl;
|
||||
auto pa_su_sc_mode_cntl = args->pa_su_sc_mode_cntl;
|
||||
auto pa_su_vtx_cntl = args->pa_su_vtx_cntl;
|
||||
|
||||
// Obtain the original viewport values in a normalized way.
|
||||
float scale_xy[] = {
|
||||
pa_cl_vte_cntl.vport_x_scale_ena ? regs[XE_GPU_REG_PA_CL_VPORT_XSCALE].f32
|
||||
: 1.0f,
|
||||
pa_cl_vte_cntl.vport_y_scale_ena ? regs[XE_GPU_REG_PA_CL_VPORT_YSCALE].f32
|
||||
: 1.0f,
|
||||
|
||||
pa_cl_vte_cntl.vport_x_scale_ena ? args->PA_CL_VPORT_XSCALE : 1.0f,
|
||||
pa_cl_vte_cntl.vport_y_scale_ena ? args->PA_CL_VPORT_YSCALE : 1.0f,
|
||||
};
|
||||
float scale_z = pa_cl_vte_cntl.vport_z_scale_ena
|
||||
? regs[XE_GPU_REG_PA_CL_VPORT_ZSCALE].f32
|
||||
: 1.0f;
|
||||
float scale_z =
|
||||
pa_cl_vte_cntl.vport_z_scale_ena ? args->PA_CL_VPORT_ZSCALE : 1.0f;
|
||||
|
||||
float offset_base_xy[] = {
|
||||
pa_cl_vte_cntl.vport_x_offset_ena
|
||||
? regs[XE_GPU_REG_PA_CL_VPORT_XOFFSET].f32
|
||||
: 0.0f,
|
||||
pa_cl_vte_cntl.vport_y_offset_ena
|
||||
? regs[XE_GPU_REG_PA_CL_VPORT_YOFFSET].f32
|
||||
: 0.0f,
|
||||
pa_cl_vte_cntl.vport_x_offset_ena ? args->PA_CL_VPORT_XOFFSET : 0.0f,
|
||||
pa_cl_vte_cntl.vport_y_offset_ena ? args->PA_CL_VPORT_YOFFSET : 0.0f,
|
||||
};
|
||||
float offset_z = pa_cl_vte_cntl.vport_z_offset_ena
|
||||
? regs[XE_GPU_REG_PA_CL_VPORT_ZOFFSET].f32
|
||||
: 0.0f;
|
||||
float offset_z =
|
||||
pa_cl_vte_cntl.vport_z_offset_ena ? args->PA_CL_VPORT_ZOFFSET : 0.0f;
|
||||
// Calculate all the integer.0 or integer.5 offsetting exactly at full
|
||||
// precision, separately so it can be used in other integer calculations
|
||||
// without double rounding if needed.
|
||||
float offset_add_xy[2] = {};
|
||||
if (pa_su_sc_mode_cntl.vtx_window_offset_enable) {
|
||||
auto pa_sc_window_offset = regs.Get<reg::PA_SC_WINDOW_OFFSET>();
|
||||
auto pa_sc_window_offset = args->pa_sc_window_offset;
|
||||
offset_add_xy[0] += float(pa_sc_window_offset.window_x_offset);
|
||||
offset_add_xy[1] += float(pa_sc_window_offset.window_y_offset);
|
||||
}
|
||||
@@ -346,8 +340,11 @@ void GetHostViewportInfo(const RegisterFile& regs,
|
||||
|
||||
// The maximum value is at least the maximum host render target size anyway -
|
||||
// and a guest pixel is always treated as a whole with resolution scaling.
|
||||
uint32_t xy_max_unscaled[] = {x_max / draw_resolution_scale_x,
|
||||
y_max / draw_resolution_scale_y};
|
||||
// cbrispy: todo, this integer divides show up high on the profiler somehow
|
||||
// (it was a very long session, too)
|
||||
uint32_t xy_max_unscaled[] = {
|
||||
args->draw_resolution_scale_x_divisor.Apply(args->x_max),
|
||||
args->draw_resolution_scale_y_divisor.Apply(args->y_max)};
|
||||
assert_not_zero(xy_max_unscaled[0]);
|
||||
assert_not_zero(xy_max_unscaled[1]);
|
||||
|
||||
@@ -367,9 +364,11 @@ void GetHostViewportInfo(const RegisterFile& regs,
|
||||
std::min(xenos::kTexture2DCubeMaxWidthHeight, xy_max_unscaled[i]);
|
||||
viewport_info_out.xy_extent[i] =
|
||||
extent_axis_unscaled *
|
||||
(i ? draw_resolution_scale_y : draw_resolution_scale_x);
|
||||
(i ? args->draw_resolution_scale_y : args->draw_resolution_scale_x);
|
||||
float extent_axis_unscaled_float = float(extent_axis_unscaled);
|
||||
float pixels_to_ndc_axis = 2.0f / extent_axis_unscaled_float;
|
||||
|
||||
float pixels_to_ndc_axis = ViewportRecip2_0(extent_axis_unscaled_float);
|
||||
|
||||
ndc_scale[i] = scale_xy[i] * pixels_to_ndc_axis;
|
||||
ndc_offset[i] = (offset_base_xy[i] - extent_axis_unscaled_float * 0.5f +
|
||||
offset_add_xy[i]) *
|
||||
@@ -394,7 +393,7 @@ void GetHostViewportInfo(const RegisterFile& regs,
|
||||
// doing truncation for simplicity - since maxing with 0 is done anyway
|
||||
// (we only return viewports in the positive quarter-plane).
|
||||
uint32_t axis_resolution_scale =
|
||||
i ? draw_resolution_scale_y : draw_resolution_scale_x;
|
||||
i ? args->draw_resolution_scale_y : args->draw_resolution_scale_x;
|
||||
float offset_axis = offset_base_xy[i] + offset_add_xy[i];
|
||||
float scale_axis = scale_xy[i];
|
||||
float scale_axis_abs = std::abs(scale_xy[i]);
|
||||
@@ -422,11 +421,14 @@ void GetHostViewportInfo(const RegisterFile& regs,
|
||||
// space, a region previously outside -W...W should end up within it, so
|
||||
// the scale should be < 1.
|
||||
float axis_extent_rounded = float(axis_extent_int);
|
||||
ndc_scale_axis = scale_axis * 2.0f / axis_extent_rounded;
|
||||
float inv_axis_extent_rounded =
|
||||
ArchReciprocalRefined(axis_extent_rounded);
|
||||
|
||||
ndc_scale_axis = scale_axis * 2.0f * inv_axis_extent_rounded;
|
||||
// Move the origin of the snapped coordinates back to the original one.
|
||||
ndc_offset_axis = (float(offset_axis) -
|
||||
(float(axis_0_int) + axis_extent_rounded * 0.5f)) *
|
||||
2.0f / axis_extent_rounded;
|
||||
2.0f * inv_axis_extent_rounded;
|
||||
} else {
|
||||
// Empty viewport (everything outside the viewport scissor).
|
||||
ndc_scale_axis = 1.0f;
|
||||
@@ -497,7 +499,7 @@ void GetHostViewportInfo(const RegisterFile& regs,
|
||||
ndc_scale[2] = 0.5f;
|
||||
ndc_offset[2] = 0.5f;
|
||||
}
|
||||
if (pixel_shader_writes_depth) {
|
||||
if (args->pixel_shader_writes_depth) {
|
||||
// Allow the pixel shader to write any depth value since
|
||||
// PA_SC_VPORT_ZMIN/ZMAX isn't present on the Adreno 200; guest pixel
|
||||
// shaders don't have access to the original Z in the viewport space
|
||||
@@ -515,7 +517,7 @@ void GetHostViewportInfo(const RegisterFile& regs,
|
||||
// Direct3D 12 doesn't allow reverse depth range - on some drivers it
|
||||
// works, on some drivers it doesn't, actually, but it was never
|
||||
// explicitly allowed by the specification.
|
||||
if (!allow_reverse_z && z_min > z_max) {
|
||||
if (!args->allow_reverse_z && z_min > z_max) {
|
||||
std::swap(z_min, z_max);
|
||||
ndc_scale[2] = -ndc_scale[2];
|
||||
ndc_offset[2] = 1.0f - ndc_offset[2];
|
||||
@@ -523,10 +525,9 @@ void GetHostViewportInfo(const RegisterFile& regs,
|
||||
}
|
||||
}
|
||||
|
||||
if (normalized_depth_control.z_enable &&
|
||||
regs.Get<reg::RB_DEPTH_INFO>().depth_format ==
|
||||
xenos::DepthRenderTargetFormat::kD24FS8) {
|
||||
if (convert_z_to_float24) {
|
||||
if (args->normalized_depth_control.z_enable &&
|
||||
args->depth_format == xenos::DepthRenderTargetFormat::kD24FS8) {
|
||||
if (args->convert_z_to_float24) {
|
||||
// Need to adjust the bounds that the resulting depth values will be
|
||||
// clamped to after the pixel shader. Preferring adding some error to
|
||||
// interpolated Z instead if conversion can't be done exactly, without
|
||||
@@ -537,7 +538,7 @@ void GetHostViewportInfo(const RegisterFile& regs,
|
||||
z_min = xenos::Float20e4To32(xenos::Float32To20e4(z_min, true));
|
||||
z_max = xenos::Float20e4To32(xenos::Float32To20e4(z_max, true));
|
||||
}
|
||||
if (full_float24_in_0_to_1) {
|
||||
if (args->full_float24_in_0_to_1) {
|
||||
// Remap the full [0...2) float24 range to [0...1) support data round-trip
|
||||
// during render target ownership transfer of EDRAM tiles through depth
|
||||
// input without unrestricted depth range.
|
||||
@@ -548,7 +549,7 @@ void GetHostViewportInfo(const RegisterFile& regs,
|
||||
viewport_info_out.z_min = z_min;
|
||||
viewport_info_out.z_max = z_max;
|
||||
|
||||
if (origin_bottom_left) {
|
||||
if (args->origin_bottom_left) {
|
||||
ndc_scale[1] = -ndc_scale[1];
|
||||
ndc_offset[1] = -ndc_offset[1];
|
||||
}
|
||||
@@ -557,7 +558,6 @@ void GetHostViewportInfo(const RegisterFile& regs,
|
||||
viewport_info_out.ndc_offset[i] = ndc_offset[i];
|
||||
}
|
||||
}
|
||||
|
||||
void GetScissor(const RegisterFile& regs, Scissor& scissor_out,
|
||||
bool clamp_to_surface_pitch) {
|
||||
auto pa_sc_window_scissor_tl = regs.Get<reg::PA_SC_WINDOW_SCISSOR_TL>();
|
||||
@@ -868,7 +868,7 @@ bool GetResolveInfo(const RegisterFile& regs, const Memory& memory,
|
||||
xenos::kMaxResolveSize);
|
||||
y1 = y0 + int32_t(xenos::kMaxResolveSize);
|
||||
}
|
||||
//fails in forza horizon 1
|
||||
// fails in forza horizon 1
|
||||
assert_true(x0 < x1 && y0 < y1);
|
||||
if (x0 >= x1 || y0 >= y1) {
|
||||
XELOGE("Resolve region is empty");
|
||||
|
||||
@@ -277,18 +277,151 @@ struct ViewportInfo {
|
||||
float ndc_scale[3];
|
||||
float ndc_offset[3];
|
||||
};
|
||||
static_assert(sizeof(xenos::DepthRenderTargetFormat) == sizeof(uint32_t),
|
||||
"Change in depthrendertargetformat throws off "
|
||||
"getviewportinfoargs by a bit");
|
||||
struct GetViewportInfoArgs {
|
||||
union alignas(64) {
|
||||
struct {
|
||||
// group 1
|
||||
uint32_t x_max;
|
||||
uint32_t y_max;
|
||||
union {
|
||||
struct {
|
||||
uint32_t origin_bottom_left : 1;
|
||||
uint32_t allow_reverse_z : 1;
|
||||
uint32_t convert_z_to_float24 : 1;
|
||||
uint32_t full_float24_in_0_to_1 : 1;
|
||||
uint32_t pixel_shader_writes_depth : 1;
|
||||
xenos::DepthRenderTargetFormat depth_format : 1;
|
||||
};
|
||||
uint32_t packed_portions;
|
||||
};
|
||||
reg::RB_DEPTHCONTROL normalized_depth_control;
|
||||
// group 2
|
||||
reg::PA_CL_CLIP_CNTL pa_cl_clip_cntl;
|
||||
reg::PA_CL_VTE_CNTL pa_cl_vte_cntl;
|
||||
reg::PA_SU_SC_MODE_CNTL pa_su_sc_mode_cntl;
|
||||
reg::PA_SU_VTX_CNTL pa_su_vtx_cntl;
|
||||
// group 3
|
||||
reg::PA_SC_WINDOW_OFFSET pa_sc_window_offset;
|
||||
float PA_CL_VPORT_XSCALE;
|
||||
float PA_CL_VPORT_YSCALE;
|
||||
float PA_CL_VPORT_ZSCALE;
|
||||
|
||||
float PA_CL_VPORT_XOFFSET;
|
||||
float PA_CL_VPORT_YOFFSET;
|
||||
float PA_CL_VPORT_ZOFFSET;
|
||||
uint32_t padding_set_to_0;
|
||||
};
|
||||
#if XE_ARCH_AMD64 == 1
|
||||
struct {
|
||||
__m128i first4; // x_max, y_max, packed_portions,
|
||||
// normalized_depth_control
|
||||
__m128i second4; // pa_cl_clip_cntl, pa_cl_vte_cntl, pa_su_sc_mode_cntl,
|
||||
// pa_su_vtx_cntl
|
||||
__m128i third4; // pa_sc_window_offset, PA_CL_VPORT_XSCALE,
|
||||
// PA_CL_VPORT_YSCALE, PA_CL_VPORT_ZSCALE
|
||||
__m128i last4; // PA_CL_VPORT_XOFFSET, PA_CL_VPORT_YOFFSET,
|
||||
// PA_CL_VPORT_ZOFFSET, padding_set_to_0
|
||||
};
|
||||
#endif
|
||||
};
|
||||
|
||||
// everything that follows here does not need to be compared
|
||||
uint32_t draw_resolution_scale_x;
|
||||
uint32_t draw_resolution_scale_y;
|
||||
divisors::MagicDiv draw_resolution_scale_x_divisor;
|
||||
divisors::MagicDiv draw_resolution_scale_y_divisor;
|
||||
void Setup(uint32_t _draw_resolution_scale_x,
|
||||
uint32_t _draw_resolution_scale_y,
|
||||
divisors::MagicDiv _draw_resolution_scale_x_divisor,
|
||||
divisors::MagicDiv _draw_resolution_scale_y_divisor,
|
||||
bool _origin_bottom_left, uint32_t _x_max, uint32_t _y_max,
|
||||
bool _allow_reverse_z,
|
||||
reg::RB_DEPTHCONTROL _normalized_depth_control,
|
||||
bool _convert_z_to_float24, bool _full_float24_in_0_to_1,
|
||||
bool _pixel_shader_writes_depth) {
|
||||
packed_portions = 0;
|
||||
padding_set_to_0 = 0; // important to zero this
|
||||
draw_resolution_scale_x = _draw_resolution_scale_x;
|
||||
draw_resolution_scale_y = _draw_resolution_scale_y;
|
||||
draw_resolution_scale_x_divisor = _draw_resolution_scale_x_divisor;
|
||||
draw_resolution_scale_y_divisor = _draw_resolution_scale_y_divisor;
|
||||
origin_bottom_left = _origin_bottom_left;
|
||||
x_max = _x_max;
|
||||
y_max = _y_max;
|
||||
allow_reverse_z = _allow_reverse_z;
|
||||
normalized_depth_control = _normalized_depth_control;
|
||||
convert_z_to_float24 = _convert_z_to_float24;
|
||||
full_float24_in_0_to_1 = _full_float24_in_0_to_1;
|
||||
pixel_shader_writes_depth = _pixel_shader_writes_depth;
|
||||
}
|
||||
|
||||
void SetupRegisterValues(const RegisterFile& regs) {
|
||||
pa_cl_clip_cntl = regs.Get<reg::PA_CL_CLIP_CNTL>();
|
||||
pa_cl_vte_cntl = regs.Get<reg::PA_CL_VTE_CNTL>();
|
||||
pa_su_sc_mode_cntl = regs.Get<reg::PA_SU_SC_MODE_CNTL>();
|
||||
pa_su_vtx_cntl = regs.Get<reg::PA_SU_VTX_CNTL>();
|
||||
PA_CL_VPORT_XSCALE = regs[XE_GPU_REG_PA_CL_VPORT_XSCALE].f32;
|
||||
PA_CL_VPORT_YSCALE = regs[XE_GPU_REG_PA_CL_VPORT_YSCALE].f32;
|
||||
PA_CL_VPORT_ZSCALE = regs[XE_GPU_REG_PA_CL_VPORT_ZSCALE].f32;
|
||||
PA_CL_VPORT_XOFFSET = regs[XE_GPU_REG_PA_CL_VPORT_XOFFSET].f32;
|
||||
PA_CL_VPORT_YOFFSET = regs[XE_GPU_REG_PA_CL_VPORT_YOFFSET].f32;
|
||||
PA_CL_VPORT_ZOFFSET = regs[XE_GPU_REG_PA_CL_VPORT_ZOFFSET].f32;
|
||||
pa_sc_window_offset = regs.Get<reg::PA_SC_WINDOW_OFFSET>();
|
||||
depth_format = regs.Get<reg::RB_DEPTH_INFO>().depth_format;
|
||||
}
|
||||
XE_FORCEINLINE
|
||||
bool operator==(const GetViewportInfoArgs& prev) {
|
||||
#if XE_ARCH_AMD64 == 0
|
||||
bool result = true;
|
||||
|
||||
auto accum_eq = [&result](auto x, auto y) { result &= (x == y); };
|
||||
|
||||
#define EQC(field) accum_eq(field, prev.field)
|
||||
EQC(x_max);
|
||||
EQC(y_max);
|
||||
EQC(packed_portions);
|
||||
EQC(normalized_depth_control.value);
|
||||
EQC(pa_cl_clip_cntl.value);
|
||||
EQC(pa_cl_vte_cntl.value);
|
||||
|
||||
EQC(pa_su_sc_mode_cntl.value);
|
||||
EQC(pa_su_vtx_cntl.value);
|
||||
EQC(PA_CL_VPORT_XSCALE);
|
||||
EQC(PA_CL_VPORT_YSCALE);
|
||||
EQC(PA_CL_VPORT_ZSCALE);
|
||||
EQC(PA_CL_VPORT_XOFFSET);
|
||||
EQC(PA_CL_VPORT_YOFFSET);
|
||||
EQC(PA_CL_VPORT_ZOFFSET);
|
||||
EQC(pa_sc_window_offset.value);
|
||||
|
||||
#undef EQC
|
||||
return result;
|
||||
#else
|
||||
__m128i mask1 = _mm_cmpeq_epi32(first4, prev.first4);
|
||||
__m128i mask2 = _mm_cmpeq_epi32(second4, prev.second4);
|
||||
|
||||
__m128i mask3 = _mm_cmpeq_epi32(third4, prev.third4);
|
||||
__m128i unified1 = _mm_and_si128(mask1, mask2);
|
||||
__m128i mask4 = _mm_cmpeq_epi32(last4, prev.last4);
|
||||
|
||||
__m128i unified2 = _mm_and_si128(unified1, mask3);
|
||||
|
||||
__m128i unified3 = _mm_and_si128(unified2, mask4);
|
||||
|
||||
return _mm_movemask_epi8(unified3) == 0xFFFF;
|
||||
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
// Converts the guest viewport (or fakes one if drawing without a viewport) to
|
||||
// a viewport, plus values to multiply-add the returned position by, usable on
|
||||
// host graphics APIs such as Direct3D 11+ and Vulkan, also forcing it to the
|
||||
// Direct3D clip space with 0...W Z rather than -W...W.
|
||||
void GetHostViewportInfo(const RegisterFile& regs,
|
||||
uint32_t draw_resolution_scale_x,
|
||||
uint32_t draw_resolution_scale_y,
|
||||
bool origin_bottom_left, uint32_t x_max,
|
||||
uint32_t y_max, bool allow_reverse_z,
|
||||
reg::RB_DEPTHCONTROL normalized_depth_control,
|
||||
bool convert_z_to_float24, bool full_float24_in_0_to_1,
|
||||
bool pixel_shader_writes_depth,
|
||||
void GetHostViewportInfo(GetViewportInfoArgs* XE_RESTRICT args,
|
||||
ViewportInfo& viewport_info_out);
|
||||
|
||||
struct Scissor {
|
||||
|
||||
@@ -813,20 +813,22 @@ bool RenderTargetCache::Update(bool is_rasterization_done,
|
||||
}
|
||||
// Make sure the same render target isn't bound into two different slots
|
||||
// over time.
|
||||
for (uint32_t i = 1; are_accumulated_render_targets_valid_ &&
|
||||
i < 1 + xenos::kMaxColorRenderTargets;
|
||||
++i) {
|
||||
const RenderTarget* render_target =
|
||||
last_update_accumulated_render_targets_[i];
|
||||
if (!render_target) {
|
||||
continue;
|
||||
}
|
||||
for (uint32_t j = 0; j < i; ++j) {
|
||||
if (last_update_accumulated_render_targets_[j] == render_target) {
|
||||
are_accumulated_render_targets_valid_ = false;
|
||||
break;
|
||||
// chrispy: this needs optimization!
|
||||
if (are_accumulated_render_targets_valid_) {
|
||||
for (uint32_t i = 1; i < 1 + xenos::kMaxColorRenderTargets; ++i) {
|
||||
const RenderTarget* render_target =
|
||||
last_update_accumulated_render_targets_[i];
|
||||
if (!render_target) {
|
||||
continue;
|
||||
}
|
||||
for (uint32_t j = 0; j < i; ++j) {
|
||||
if (last_update_accumulated_render_targets_[j] == render_target) {
|
||||
are_accumulated_render_targets_valid_ = false;
|
||||
goto exit_slot_check_loop;
|
||||
}
|
||||
}
|
||||
}
|
||||
exit_slot_check_loop:;
|
||||
}
|
||||
}
|
||||
if (!are_accumulated_render_targets_valid_) {
|
||||
|
||||
@@ -154,7 +154,9 @@ TextureCache::TextureCache(const RegisterFile& register_file,
|
||||
: register_file_(register_file),
|
||||
shared_memory_(shared_memory),
|
||||
draw_resolution_scale_x_(draw_resolution_scale_x),
|
||||
draw_resolution_scale_y_(draw_resolution_scale_y) {
|
||||
draw_resolution_scale_y_(draw_resolution_scale_y),
|
||||
draw_resolution_scale_x_divisor_(draw_resolution_scale_x),
|
||||
draw_resolution_scale_y_divisor_(draw_resolution_scale_y) {
|
||||
assert_true(draw_resolution_scale_x >= 1);
|
||||
assert_true(draw_resolution_scale_x <= kMaxDrawResolutionScaleAlongAxis);
|
||||
assert_true(draw_resolution_scale_y >= 1);
|
||||
@@ -187,6 +189,7 @@ bool TextureCache::GetConfigDrawResolutionScale(uint32_t& x_out,
|
||||
uint32_t(std::max(INT32_C(1), cvars::draw_resolution_scale_x));
|
||||
uint32_t config_y =
|
||||
uint32_t(std::max(INT32_C(1), cvars::draw_resolution_scale_y));
|
||||
|
||||
uint32_t clamped_x = std::min(kMaxDrawResolutionScaleAlongAxis, config_x);
|
||||
uint32_t clamped_y = std::min(kMaxDrawResolutionScaleAlongAxis, config_y);
|
||||
x_out = clamped_x;
|
||||
@@ -552,8 +555,7 @@ void TextureCache::Texture::MarkAsUsed() {
|
||||
}
|
||||
|
||||
void TextureCache::Texture::WatchCallback(
|
||||
[[maybe_unused]] const global_unique_lock_type& global_lock,
|
||||
bool is_mip) {
|
||||
[[maybe_unused]] const global_unique_lock_type& global_lock, bool is_mip) {
|
||||
if (is_mip) {
|
||||
assert_not_zero(GetGuestMipsSize());
|
||||
mips_outdated_ = true;
|
||||
@@ -566,8 +568,8 @@ void TextureCache::Texture::WatchCallback(
|
||||
}
|
||||
|
||||
void TextureCache::WatchCallback(const global_unique_lock_type& global_lock,
|
||||
void* context,
|
||||
void* data, uint64_t argument, bool invalidated_by_gpu) {
|
||||
void* context, void* data, uint64_t argument,
|
||||
bool invalidated_by_gpu) {
|
||||
Texture& texture = *static_cast<Texture*>(context);
|
||||
texture.WatchCallback(global_lock, argument != 0);
|
||||
texture.texture_cache().texture_became_outdated_.store(
|
||||
@@ -910,8 +912,8 @@ void TextureCache::ScaledResolveGlobalWatchCallbackThunk(
|
||||
}
|
||||
|
||||
void TextureCache::ScaledResolveGlobalWatchCallback(
|
||||
const global_unique_lock_type& global_lock,
|
||||
uint32_t address_first, uint32_t address_last, bool invalidated_by_gpu) {
|
||||
const global_unique_lock_type& global_lock, uint32_t address_first,
|
||||
uint32_t address_last, bool invalidated_by_gpu) {
|
||||
assert_true(IsDrawResolutionScaled());
|
||||
if (invalidated_by_gpu) {
|
||||
// Resolves themselves do exactly the opposite of what this should do.
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/base/hash.h"
|
||||
#include "xenia/base/math.h"
|
||||
#include "xenia/base/mutex.h"
|
||||
#include "xenia/gpu/register_file.h"
|
||||
#include "xenia/gpu/shared_memory.h"
|
||||
@@ -70,6 +71,14 @@ class TextureCache {
|
||||
static bool GetConfigDrawResolutionScale(uint32_t& x_out, uint32_t& y_out);
|
||||
uint32_t draw_resolution_scale_x() const { return draw_resolution_scale_x_; }
|
||||
uint32_t draw_resolution_scale_y() const { return draw_resolution_scale_y_; }
|
||||
|
||||
divisors::MagicDiv draw_resolution_scale_x_divisor() const {
|
||||
return draw_resolution_scale_x_divisor_;
|
||||
}
|
||||
divisors::MagicDiv draw_resolution_scale_y_divisor() const {
|
||||
return draw_resolution_scale_y_divisor_;
|
||||
}
|
||||
|
||||
bool IsDrawResolutionScaled() const {
|
||||
return draw_resolution_scale_x_ > 1 || draw_resolution_scale_y_ > 1;
|
||||
}
|
||||
@@ -576,8 +585,8 @@ class TextureCache {
|
||||
|
||||
// Shared memory callback for texture data invalidation.
|
||||
static void WatchCallback(const global_unique_lock_type& global_lock,
|
||||
void* context,
|
||||
void* data, uint64_t argument, bool invalidated_by_gpu);
|
||||
void* context, void* data, uint64_t argument,
|
||||
bool invalidated_by_gpu);
|
||||
|
||||
// Checks if there are any pages that contain scaled resolve data within the
|
||||
// range.
|
||||
@@ -588,14 +597,15 @@ class TextureCache {
|
||||
const global_unique_lock_type& global_lock, void* context,
|
||||
uint32_t address_first, uint32_t address_last, bool invalidated_by_gpu);
|
||||
void ScaledResolveGlobalWatchCallback(
|
||||
const global_unique_lock_type& global_lock,
|
||||
uint32_t address_first, uint32_t address_last, bool invalidated_by_gpu);
|
||||
const global_unique_lock_type& global_lock, uint32_t address_first,
|
||||
uint32_t address_last, bool invalidated_by_gpu);
|
||||
|
||||
const RegisterFile& register_file_;
|
||||
SharedMemory& shared_memory_;
|
||||
uint32_t draw_resolution_scale_x_;
|
||||
uint32_t draw_resolution_scale_y_;
|
||||
|
||||
divisors::MagicDiv draw_resolution_scale_x_divisor_;
|
||||
divisors::MagicDiv draw_resolution_scale_y_divisor_;
|
||||
static const LoadShaderInfo load_shader_info_[kLoadShaderCount];
|
||||
|
||||
xe::global_critical_region global_critical_region_;
|
||||
|
||||
@@ -2366,6 +2366,7 @@ bool VulkanCommandProcessor::IssueDraw(xenos::PrimitiveType prim_type,
|
||||
|
||||
// Get dynamic rasterizer state.
|
||||
draw_util::ViewportInfo viewport_info;
|
||||
|
||||
// Just handling maxViewportDimensions is enough - viewportBoundsRange[1] must
|
||||
// be at least 2 * max(maxViewportDimensions[0...1]) - 1, and
|
||||
// maxViewportDimensions must be greater than or equal to the size of the
|
||||
@@ -2382,11 +2383,16 @@ bool VulkanCommandProcessor::IssueDraw(xenos::PrimitiveType prim_type,
|
||||
// life. Or even disregard the viewport bounds range in the fragment shader
|
||||
// interlocks case completely - apply the viewport and the scissor offset
|
||||
// directly to pixel address and to things like ps_param_gen.
|
||||
draw_util::GetHostViewportInfo(
|
||||
regs, 1, 1, false, device_limits.maxViewportDimensions[0],
|
||||
device_limits.maxViewportDimensions[1], true, normalized_depth_control,
|
||||
false, host_render_targets_used,
|
||||
pixel_shader && pixel_shader->writes_depth(), viewport_info);
|
||||
draw_util::GetViewportInfoArgs gviargs{};
|
||||
gviargs.Setup(1, 1, divisors::MagicDiv{1}, divisors::MagicDiv{1}, false,
|
||||
device_limits.maxViewportDimensions[0],
|
||||
|
||||
device_limits.maxViewportDimensions[1], true,
|
||||
normalized_depth_control, false, host_render_targets_used,
|
||||
pixel_shader && pixel_shader->writes_depth());
|
||||
gviargs.SetupRegisterValues(regs);
|
||||
|
||||
draw_util::GetHostViewportInfo(&gviargs, viewport_info);
|
||||
|
||||
// Update dynamic graphics pipeline state.
|
||||
UpdateDynamicState(viewport_info, primitive_polygonal,
|
||||
|
||||
@@ -326,7 +326,14 @@ constexpr bool IsColorRenderTargetFormat64bpp(ColorRenderTargetFormat format) {
|
||||
format == ColorRenderTargetFormat::k_32_32_FLOAT;
|
||||
}
|
||||
|
||||
inline uint32_t GetColorRenderTargetFormatComponentCount(
|
||||
// if 0, 1
|
||||
// if 1, 2
|
||||
// if 3, 4
|
||||
// 2 bits per entry, shift and add 1
|
||||
|
||||
using ColorFormatComponentTable = uint32_t;
|
||||
|
||||
static constexpr uint32_t GetComponentCountConst(
|
||||
ColorRenderTargetFormat format) {
|
||||
switch (format) {
|
||||
case ColorRenderTargetFormat::k_8_8_8_8:
|
||||
@@ -337,19 +344,51 @@ inline uint32_t GetColorRenderTargetFormatComponentCount(
|
||||
case ColorRenderTargetFormat::k_16_16_16_16_FLOAT:
|
||||
case ColorRenderTargetFormat::k_2_10_10_10_AS_10_10_10_10:
|
||||
case ColorRenderTargetFormat::k_2_10_10_10_FLOAT_AS_16_16_16_16:
|
||||
return 4;
|
||||
return 4 - 1;
|
||||
case ColorRenderTargetFormat::k_16_16:
|
||||
case ColorRenderTargetFormat::k_16_16_FLOAT:
|
||||
case ColorRenderTargetFormat::k_32_32_FLOAT:
|
||||
return 2;
|
||||
return 2 - 1;
|
||||
case ColorRenderTargetFormat::k_32_FLOAT:
|
||||
return 1;
|
||||
return 1 - 1;
|
||||
default:
|
||||
assert_unhandled_case(format);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
namespace detail {
|
||||
static constexpr uint32_t encode_format_component_table() {
|
||||
uint32_t result = 0;
|
||||
|
||||
#define ADDFORMAT(name) \
|
||||
result |= GetComponentCountConst(ColorRenderTargetFormat::name) \
|
||||
<< (static_cast<uint32_t>(ColorRenderTargetFormat::name) * 2)
|
||||
ADDFORMAT(k_8_8_8_8);
|
||||
ADDFORMAT(k_8_8_8_8_GAMMA);
|
||||
ADDFORMAT(k_2_10_10_10);
|
||||
ADDFORMAT(k_2_10_10_10_FLOAT);
|
||||
|
||||
ADDFORMAT(k_16_16_16_16);
|
||||
ADDFORMAT(k_16_16_16_16_FLOAT);
|
||||
ADDFORMAT(k_2_10_10_10_AS_10_10_10_10);
|
||||
ADDFORMAT(k_2_10_10_10_FLOAT_AS_16_16_16_16);
|
||||
|
||||
ADDFORMAT(k_16_16);
|
||||
ADDFORMAT(k_16_16_FLOAT);
|
||||
ADDFORMAT(k_32_32_FLOAT);
|
||||
ADDFORMAT(k_32_FLOAT);
|
||||
return result;
|
||||
}
|
||||
constexpr uint32_t color_format_component_table =
|
||||
encode_format_component_table();
|
||||
|
||||
} // namespace detail
|
||||
constexpr uint32_t GetColorRenderTargetFormatComponentCount(
|
||||
ColorRenderTargetFormat format) {
|
||||
return ((detail::color_format_component_table >>
|
||||
(static_cast<uint32_t>(format) * 2)) &
|
||||
0b11) +
|
||||
1;
|
||||
}
|
||||
// Returns the version of the format with the same packing and meaning of values
|
||||
// stored in it, but without blending precision modifiers.
|
||||
constexpr ColorRenderTargetFormat GetStorageColorFormat(
|
||||
|
||||
Reference in New Issue
Block a user