mirror of
https://github.com/xenia-project/xenia.git
synced 2025-12-06 07:12:03 +01:00
[SPIR-V] Store vfetch_full address in a variable
This commit is contained in:
parent
e447cf6ed8
commit
8ccb00d03d
|
|
@ -2,7 +2,7 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* Xenia : Xbox 360 Emulator Research Project *
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* Copyright 2021 Ben Vanik. All rights reserved. *
|
* Copyright 2022 Ben Vanik. All rights reserved. *
|
||||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
@ -396,6 +396,9 @@ void SpirvShaderTranslator::StartTranslation() {
|
||||||
var_main_previous_scalar_ = builder_->createVariable(
|
var_main_previous_scalar_ = builder_->createVariable(
|
||||||
spv::NoPrecision, spv::StorageClassFunction, type_float_,
|
spv::NoPrecision, spv::StorageClassFunction, type_float_,
|
||||||
"xe_var_previous_scalar", const_float_0_);
|
"xe_var_previous_scalar", const_float_0_);
|
||||||
|
var_main_vfetch_address_ = builder_->createVariable(
|
||||||
|
spv::NoPrecision, spv::StorageClassFunction, type_int_,
|
||||||
|
"xe_var_vfetch_address", const_int_0_);
|
||||||
uint32_t register_array_size = register_count();
|
uint32_t register_array_size = register_count();
|
||||||
if (register_array_size) {
|
if (register_array_size) {
|
||||||
id_vector_temp_.clear();
|
id_vector_temp_.clear();
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* Xenia : Xbox 360 Emulator Research Project *
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* Copyright 2021 Ben Vanik. All rights reserved. *
|
* Copyright 2022 Ben Vanik. All rights reserved. *
|
||||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
@ -439,6 +439,9 @@ class SpirvShaderTranslator : public ShaderTranslator {
|
||||||
spv::Id var_main_address_absolute_;
|
spv::Id var_main_address_absolute_;
|
||||||
// float.
|
// float.
|
||||||
spv::Id var_main_previous_scalar_;
|
spv::Id var_main_previous_scalar_;
|
||||||
|
// `base + index * stride` in dwords from the last vfetch_full as it may be
|
||||||
|
// needed by vfetch_mini - int.
|
||||||
|
spv::Id var_main_vfetch_address_;
|
||||||
// float4[register_count()].
|
// float4[register_count()].
|
||||||
spv::Id var_main_registers_;
|
spv::Id var_main_registers_;
|
||||||
// VS only - float3 (special exports).
|
// VS only - float3 (special exports).
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* Xenia : Xbox 360 Emulator Research Project *
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* Copyright 2020 Ben Vanik. All rights reserved. *
|
* Copyright 2022 Ben Vanik. All rights reserved. *
|
||||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
@ -27,7 +27,9 @@ void SpirvShaderTranslator::ProcessVertexFetchInstruction(
|
||||||
uint32_t used_result_components = instr.result.GetUsedResultComponents();
|
uint32_t used_result_components = instr.result.GetUsedResultComponents();
|
||||||
uint32_t needed_words = xenos::GetVertexFormatNeededWords(
|
uint32_t needed_words = xenos::GetVertexFormatNeededWords(
|
||||||
instr.attributes.data_format, used_result_components);
|
instr.attributes.data_format, used_result_components);
|
||||||
if (!needed_words) {
|
// If this is vfetch_full, the address may still be needed for vfetch_mini -
|
||||||
|
// don't exit before calculating the address.
|
||||||
|
if (!needed_words && instr.is_mini_fetch) {
|
||||||
// Nothing to load - just constant 0/1 writes, or the swizzle includes only
|
// Nothing to load - just constant 0/1 writes, or the swizzle includes only
|
||||||
// components that don't exist in the format (writing zero instead of them).
|
// components that don't exist in the format (writing zero instead of them).
|
||||||
// Unpacking assumes at least some word is needed.
|
// Unpacking assumes at least some word is needed.
|
||||||
|
|
@ -37,56 +39,71 @@ void SpirvShaderTranslator::ProcessVertexFetchInstruction(
|
||||||
|
|
||||||
EnsureBuildPointAvailable();
|
EnsureBuildPointAvailable();
|
||||||
|
|
||||||
// Get the base address in dwords from the bits 2:31 of the first fetch
|
|
||||||
// constant word.
|
|
||||||
uint32_t fetch_constant_word_0_index = instr.operands[1].storage_index << 1;
|
uint32_t fetch_constant_word_0_index = instr.operands[1].storage_index << 1;
|
||||||
id_vector_temp_.clear();
|
|
||||||
id_vector_temp_.reserve(3);
|
spv::Id address;
|
||||||
// The only element of the fetch constant buffer.
|
if (instr.is_mini_fetch) {
|
||||||
id_vector_temp_.push_back(const_int_0_);
|
// `base + index * stride` loaded by vfetch_full.
|
||||||
// Vector index.
|
address = builder_->createLoad(var_main_vfetch_address_, spv::NoPrecision);
|
||||||
id_vector_temp_.push_back(
|
} else {
|
||||||
builder_->makeIntConstant(int(fetch_constant_word_0_index >> 2)));
|
// Get the base address in dwords from the bits 2:31 of the first fetch
|
||||||
// Component index.
|
// constant word.
|
||||||
id_vector_temp_.push_back(
|
|
||||||
builder_->makeIntConstant(int(fetch_constant_word_0_index & 3)));
|
|
||||||
spv::Id fetch_constant_word_0 = builder_->createLoad(
|
|
||||||
builder_->createAccessChain(spv::StorageClassUniform,
|
|
||||||
uniform_fetch_constants_, id_vector_temp_),
|
|
||||||
spv::NoPrecision);
|
|
||||||
// TODO(Triang3l): Verify the fetch constant type (that it's a vertex fetch,
|
|
||||||
// not a texture fetch) here instead of dropping draws with invalid vertex
|
|
||||||
// fetch constants on the CPU when proper bound checks are added - vfetch may
|
|
||||||
// be conditional, so fetch constants may also be used conditionally.
|
|
||||||
spv::Id address = builder_->createUnaryOp(
|
|
||||||
spv::OpBitcast, type_int_,
|
|
||||||
builder_->createBinOp(spv::OpShiftRightLogical, type_uint_,
|
|
||||||
fetch_constant_word_0,
|
|
||||||
builder_->makeUintConstant(2)));
|
|
||||||
if (instr.attributes.stride) {
|
|
||||||
// Convert the index to an integer by flooring or by rounding to the nearest
|
|
||||||
// (as floor(index + 0.5) because rounding to the nearest even makes no
|
|
||||||
// sense for addressing, both 1.5 and 2.5 would be 2).
|
|
||||||
// http://web.archive.org/web/20100302145413/http://msdn.microsoft.com:80/en-us/library/bb313960.aspx
|
|
||||||
spv::Id index = GetOperandComponents(LoadOperandStorage(instr.operands[0]),
|
|
||||||
instr.operands[0], 0b0001);
|
|
||||||
if (instr.attributes.is_index_rounded) {
|
|
||||||
index = builder_->createBinOp(spv::OpFAdd, type_float_, index,
|
|
||||||
builder_->makeFloatConstant(0.5f));
|
|
||||||
builder_->addDecoration(index, spv::DecorationNoContraction);
|
|
||||||
}
|
|
||||||
id_vector_temp_.clear();
|
id_vector_temp_.clear();
|
||||||
id_vector_temp_.push_back(index);
|
id_vector_temp_.reserve(3);
|
||||||
index = builder_->createUnaryOp(
|
// The only element of the fetch constant buffer.
|
||||||
spv::OpConvertFToS, type_int_,
|
id_vector_temp_.push_back(const_int_0_);
|
||||||
builder_->createBuiltinCall(type_float_, ext_inst_glsl_std_450_,
|
// Vector index.
|
||||||
GLSLstd450Floor, id_vector_temp_));
|
id_vector_temp_.push_back(
|
||||||
if (instr.attributes.stride > 1) {
|
builder_->makeIntConstant(int(fetch_constant_word_0_index >> 2)));
|
||||||
index = builder_->createBinOp(
|
// Component index.
|
||||||
spv::OpIMul, type_int_, index,
|
id_vector_temp_.push_back(
|
||||||
builder_->makeIntConstant(int(instr.attributes.stride)));
|
builder_->makeIntConstant(int(fetch_constant_word_0_index & 3)));
|
||||||
|
spv::Id fetch_constant_word_0 = builder_->createLoad(
|
||||||
|
builder_->createAccessChain(spv::StorageClassUniform,
|
||||||
|
uniform_fetch_constants_, id_vector_temp_),
|
||||||
|
spv::NoPrecision);
|
||||||
|
// TODO(Triang3l): Verify the fetch constant type (that it's a vertex fetch,
|
||||||
|
// not a texture fetch) here instead of dropping draws with invalid vertex
|
||||||
|
// fetch constants on the CPU when proper bound checks are added - vfetch
|
||||||
|
// may be conditional, so fetch constants may also be used conditionally.
|
||||||
|
address = builder_->createUnaryOp(
|
||||||
|
spv::OpBitcast, type_int_,
|
||||||
|
builder_->createBinOp(spv::OpShiftRightLogical, type_uint_,
|
||||||
|
fetch_constant_word_0,
|
||||||
|
builder_->makeUintConstant(2)));
|
||||||
|
if (instr.attributes.stride) {
|
||||||
|
// Convert the index to an integer by flooring or by rounding to the
|
||||||
|
// nearest (as floor(index + 0.5) because rounding to the nearest even
|
||||||
|
// makes no sense for addressing, both 1.5 and 2.5 would be 2).
|
||||||
|
spv::Id index = GetOperandComponents(
|
||||||
|
LoadOperandStorage(instr.operands[0]), instr.operands[0], 0b0001);
|
||||||
|
if (instr.attributes.is_index_rounded) {
|
||||||
|
index = builder_->createBinOp(spv::OpFAdd, type_float_, index,
|
||||||
|
builder_->makeFloatConstant(0.5f));
|
||||||
|
builder_->addDecoration(index, spv::DecorationNoContraction);
|
||||||
|
}
|
||||||
|
id_vector_temp_.clear();
|
||||||
|
id_vector_temp_.push_back(index);
|
||||||
|
index = builder_->createUnaryOp(
|
||||||
|
spv::OpConvertFToS, type_int_,
|
||||||
|
builder_->createBuiltinCall(type_float_, ext_inst_glsl_std_450_,
|
||||||
|
GLSLstd450Floor, id_vector_temp_));
|
||||||
|
if (instr.attributes.stride > 1) {
|
||||||
|
index = builder_->createBinOp(
|
||||||
|
spv::OpIMul, type_int_, index,
|
||||||
|
builder_->makeIntConstant(int(instr.attributes.stride)));
|
||||||
|
}
|
||||||
|
address = builder_->createBinOp(spv::OpIAdd, type_int_, address, index);
|
||||||
}
|
}
|
||||||
address = builder_->createBinOp(spv::OpIAdd, type_int_, address, index);
|
// Store the address for the subsequent vfetch_mini.
|
||||||
|
builder_->createStore(address, var_main_vfetch_address_);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!needed_words) {
|
||||||
|
// The vfetch_full address has been loaded for the subsequent vfetch_mini,
|
||||||
|
// but there's no data to load.
|
||||||
|
StoreResult(instr.result, spv::NoResult);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the needed words.
|
// Load the needed words.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue