458 lines
17 KiB
C++
458 lines
17 KiB
C++
/**
|
|
******************************************************************************
|
|
* Xenia : Xbox 360 Emulator Research Project *
|
|
******************************************************************************
|
|
* Copyright 2018 Ben Vanik. All rights reserved. *
|
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
|
******************************************************************************
|
|
*/
|
|
|
|
#include "xenia/gpu/dxbc_shader_translator.h"
|
|
|
|
namespace xe {
|
|
namespace gpu {
|
|
using namespace ucode;
|
|
|
|
void DxbcShaderTranslator::ExportToMemory_PackFixed32(
|
|
const uint32_t* eM_temps, uint32_t eM_count, const uint32_t bits[4],
|
|
const DxbcSrc& is_integer, const DxbcSrc& is_signed) {
|
|
// Will insert with BFI - sign extension of red will be overwritten, not
|
|
// truncated.
|
|
assert_not_zero(bits[0]);
|
|
assert_true(bits[0] + bits[1] + bits[2] + bits[3] == 32);
|
|
uint32_t mask = 0;
|
|
for (uint32_t i = 0; i < 4; ++i) {
|
|
if (bits[i]) {
|
|
mask |= 1 << i;
|
|
}
|
|
}
|
|
DxbcOpIf(true, is_signed);
|
|
{
|
|
float range[4];
|
|
for (uint32_t i = 0; i < 4; ++i) {
|
|
range[i] = bits[i] ? float((uint32_t(1) << (bits[i] - 1)) - 1) : 0.0f;
|
|
}
|
|
DxbcSrc range_src(DxbcSrc::LP(range));
|
|
DxbcOpIf(false, is_integer);
|
|
for (uint32_t i = 0; i < eM_count; ++i) {
|
|
uint32_t eM_temp = eM_temps[i];
|
|
DxbcOpMul(DxbcDest::R(eM_temp, mask), DxbcSrc::R(eM_temp), range_src);
|
|
}
|
|
DxbcOpEndIf();
|
|
for (uint32_t i = 0; i < eM_count; ++i) {
|
|
DxbcDest eM_dest(DxbcDest::R(eM_temps[i], mask));
|
|
DxbcSrc eM_src(DxbcSrc::R(eM_temps[i]));
|
|
DxbcOpMax(eM_dest, eM_src, -range_src);
|
|
DxbcOpMin(eM_dest, eM_src, range_src);
|
|
}
|
|
}
|
|
DxbcOpElse();
|
|
{
|
|
float range[4];
|
|
for (uint32_t i = 0; i < 4; ++i) {
|
|
range[i] = float((uint32_t(1) << bits[i]) - 1);
|
|
}
|
|
DxbcSrc range_src(DxbcSrc::LP(range));
|
|
DxbcOpIf(false, is_integer);
|
|
for (uint32_t i = 0; i < eM_count; ++i) {
|
|
uint32_t eM_temp = eM_temps[i];
|
|
DxbcOpMul(DxbcDest::R(eM_temp, mask), DxbcSrc::R(eM_temp), range_src);
|
|
}
|
|
DxbcOpEndIf();
|
|
for (uint32_t i = 0; i < eM_count; ++i) {
|
|
DxbcDest eM_dest(DxbcDest::R(eM_temps[i], mask));
|
|
DxbcSrc eM_src(DxbcSrc::R(eM_temps[i]));
|
|
DxbcOpMax(eM_dest, eM_src, DxbcSrc::LF(0.0f));
|
|
DxbcOpMin(eM_dest, eM_src, range_src);
|
|
}
|
|
}
|
|
DxbcOpEndIf();
|
|
for (uint32_t i = 0; i < eM_count; ++i) {
|
|
uint32_t eM_temp = eM_temps[i];
|
|
// Round to the nearest integer, according to the rules of handling integer
|
|
// formats in Direct3D.
|
|
DxbcOpRoundNE(DxbcDest::R(eM_temp, mask), DxbcSrc::R(eM_temp));
|
|
DxbcOpFToI(DxbcDest::R(eM_temp, mask), DxbcSrc::R(eM_temp));
|
|
DxbcDest eM_packed_dest(DxbcDest::R(eM_temp, 0b0001));
|
|
DxbcSrc eM_packed_src(DxbcSrc::R(eM_temp, DxbcSrc::kXXXX));
|
|
uint32_t offset = bits[0];
|
|
for (uint32_t j = 1; j < 4; ++j) {
|
|
if (!bits[j]) {
|
|
continue;
|
|
}
|
|
DxbcOpBFI(eM_packed_dest, DxbcSrc::LU(bits[j]), DxbcSrc::LU(offset),
|
|
DxbcSrc::R(eM_temp).Select(j), eM_packed_src);
|
|
offset += bits[j];
|
|
}
|
|
}
|
|
}
|
|
|
|
void DxbcShaderTranslator::ExportToMemory() {
|
|
if (system_temp_memexport_written_ == UINT32_MAX) {
|
|
// No exports in the shader.
|
|
return;
|
|
}
|
|
|
|
// Allocate a register for temporary values at various stages.
|
|
uint32_t control_temp = PushSystemTemp();
|
|
|
|
// Safety check if the shared memory is bound as UAV.
|
|
system_constants_used_ |= 1ull << kSysConst_Flags_Index;
|
|
DxbcOpAnd(DxbcDest::R(control_temp, 0b0001),
|
|
DxbcSrc::CB(cbuffer_index_system_constants_,
|
|
uint32_t(CbufferRegister::kSystemConstants),
|
|
kSysConst_Flags_Vec)
|
|
.Select(kSysConst_Flags_Comp),
|
|
DxbcSrc::LU(kSysFlag_SharedMemoryIsUAV));
|
|
if (IsDxbcPixelShader()) {
|
|
// Disable memexport in pixel shaders with supersampling since VPOS is
|
|
// ambiguous.
|
|
if (edram_rov_used_) {
|
|
system_constants_used_ |= 1ull
|
|
<< kSysConst_EDRAMResolutionSquareScale_Index;
|
|
DxbcOpULT(DxbcDest::R(control_temp, 0b0010),
|
|
DxbcSrc::CB(cbuffer_index_system_constants_,
|
|
uint32_t(CbufferRegister::kSystemConstants),
|
|
kSysConst_EDRAMResolutionSquareScale_Vec)
|
|
.Select(kSysConst_EDRAMResolutionSquareScale_Comp),
|
|
DxbcSrc::LU(2));
|
|
DxbcOpAnd(DxbcDest::R(control_temp, 0b0001),
|
|
DxbcSrc::R(control_temp, DxbcSrc::kXXXX),
|
|
DxbcSrc::R(control_temp, DxbcSrc::kYYYY));
|
|
} else {
|
|
// Enough to check just Y because it's scaled for both 2x and 4x.
|
|
system_constants_used_ |= 1ull << kSysConst_SampleCountLog2_Index;
|
|
DxbcOpMovC(DxbcDest::R(control_temp, 0b0001),
|
|
DxbcSrc::CB(cbuffer_index_system_constants_,
|
|
uint32_t(CbufferRegister::kSystemConstants),
|
|
kSysConst_SampleCountLog2_Vec)
|
|
.Select(kSysConst_SampleCountLog2_Comp + 1),
|
|
DxbcSrc::LU(0), DxbcSrc::R(control_temp, DxbcSrc::kXXXX));
|
|
}
|
|
}
|
|
// Check if memexport can be done.
|
|
DxbcOpIf(true, DxbcSrc::R(control_temp, DxbcSrc::kXXXX));
|
|
// control_temp.x is now free.
|
|
|
|
for (uint32_t i = 0; i < kMaxMemExports; ++i) {
|
|
uint32_t eA_temp = system_temps_memexport_address_[i];
|
|
if (eA_temp == UINT32_MAX) {
|
|
// Export not used.
|
|
continue;
|
|
}
|
|
// For simplicity of access, gather actually used eM# registers for this
|
|
// export. Zero-initialize eM_offsets because excess elements of it may be
|
|
// accessed, for stable caching.
|
|
uint32_t eM_temps[5], eM_offsets[5] = {}, eM_count = 0;
|
|
for (uint32_t j = 0; j < 5; ++j) {
|
|
uint32_t eM_temp = system_temps_memexport_data_[i][j];
|
|
if (eM_temp == UINT32_MAX) {
|
|
continue;
|
|
}
|
|
eM_temps[eM_count] = eM_temp;
|
|
eM_offsets[eM_count] = j;
|
|
++eM_count;
|
|
}
|
|
if (eM_count == 0) {
|
|
continue;
|
|
}
|
|
|
|
// Swap red and blue if needed.
|
|
DxbcOpAnd(DxbcDest::R(control_temp, 0b0001),
|
|
DxbcSrc::R(eA_temp, DxbcSrc::kZZZZ),
|
|
DxbcSrc::LU(uint32_t(1) << 19));
|
|
for (uint32_t j = 0; j < eM_count; ++j) {
|
|
uint32_t eM_temp = eM_temps[j];
|
|
DxbcOpMovC(DxbcDest::R(eM_temp, 0b0101),
|
|
DxbcSrc::R(control_temp, DxbcSrc::kXXXX),
|
|
DxbcSrc::R(eM_temp, 0b000010), DxbcSrc::R(eM_temp));
|
|
}
|
|
|
|
// Initialize element size in control_temp.x to 4 bytes as this is the most
|
|
// common size.
|
|
DxbcDest element_size_dest(DxbcDest::R(control_temp, 0b0001));
|
|
DxbcSrc element_size_src(DxbcSrc::R(control_temp, DxbcSrc::kXXXX));
|
|
DxbcOpMov(element_size_dest, DxbcSrc::LU(4));
|
|
|
|
// Each eM should get a packed value in the destination format now.
|
|
|
|
// Extract format properties to control_temp.
|
|
// Y - signedness if fixed-point.
|
|
// Z - fractional/integer if fixed-point.
|
|
// W - color format.
|
|
DxbcOpUBFE(DxbcDest::R(control_temp, 0b1110), DxbcSrc::LU(0, 1, 1, 6),
|
|
DxbcSrc::LU(0, 16, 17, 8), DxbcSrc::R(eA_temp, DxbcSrc::kZZZZ));
|
|
DxbcSrc is_signed(DxbcSrc::R(control_temp, DxbcSrc::kYYYY));
|
|
DxbcSrc is_integer(DxbcSrc::R(control_temp, DxbcSrc::kZZZZ));
|
|
// Convert and pack the format.
|
|
DxbcOpSwitch(DxbcSrc::R(control_temp, DxbcSrc::kWWWW));
|
|
// control_temp.w is now free.
|
|
{
|
|
// k_8_8_8_8
|
|
// k_8_8_8_8_AS_16_16_16_16
|
|
DxbcOpCase(DxbcSrc::LU(uint32_t(ColorFormat::k_8_8_8_8)));
|
|
DxbcOpCase(DxbcSrc::LU(uint32_t(ColorFormat::k_8_8_8_8_AS_16_16_16_16)));
|
|
{
|
|
uint32_t bits[4] = {8, 8, 8, 8};
|
|
ExportToMemory_PackFixed32(eM_temps, eM_count, bits, is_integer,
|
|
is_signed);
|
|
}
|
|
DxbcOpBreak();
|
|
|
|
// k_2_10_10_10
|
|
// k_2_10_10_10_AS_16_16_16_16
|
|
DxbcOpCase(DxbcSrc::LU(uint32_t(ColorFormat::k_2_10_10_10)));
|
|
DxbcOpCase(
|
|
DxbcSrc::LU(uint32_t(ColorFormat::k_2_10_10_10_AS_16_16_16_16)));
|
|
{
|
|
uint32_t bits[4] = {10, 10, 10, 2};
|
|
ExportToMemory_PackFixed32(eM_temps, eM_count, bits, is_integer,
|
|
is_signed);
|
|
}
|
|
DxbcOpBreak();
|
|
|
|
// k_10_11_11
|
|
// k_10_11_11_AS_16_16_16_16
|
|
DxbcOpCase(DxbcSrc::LU(uint32_t(ColorFormat::k_10_11_11)));
|
|
DxbcOpCase(DxbcSrc::LU(uint32_t(ColorFormat::k_10_11_11_AS_16_16_16_16)));
|
|
{
|
|
uint32_t bits[4] = {11, 11, 10};
|
|
ExportToMemory_PackFixed32(eM_temps, eM_count, bits, is_integer,
|
|
is_signed);
|
|
}
|
|
DxbcOpBreak();
|
|
|
|
// k_11_11_10
|
|
// k_11_11_10_AS_16_16_16_16
|
|
DxbcOpCase(DxbcSrc::LU(uint32_t(ColorFormat::k_11_11_10)));
|
|
DxbcOpCase(DxbcSrc::LU(uint32_t(ColorFormat::k_11_11_10_AS_16_16_16_16)));
|
|
{
|
|
uint32_t bits[4] = {10, 11, 11};
|
|
ExportToMemory_PackFixed32(eM_temps, eM_count, bits, is_integer,
|
|
is_signed);
|
|
}
|
|
DxbcOpBreak();
|
|
|
|
// k_16_16
|
|
DxbcOpCase(DxbcSrc::LU(uint32_t(ColorFormat::k_16_16)));
|
|
{
|
|
uint32_t bits[4] = {16, 16};
|
|
ExportToMemory_PackFixed32(eM_temps, eM_count, bits, is_integer,
|
|
is_signed);
|
|
}
|
|
DxbcOpBreak();
|
|
|
|
// k_16_16_16_16
|
|
DxbcOpCase(DxbcSrc::LU(uint32_t(ColorFormat::k_16_16_16_16)));
|
|
DxbcOpMov(element_size_dest, DxbcSrc::LU(8));
|
|
DxbcOpIf(true, is_signed);
|
|
{
|
|
DxbcOpIf(false, is_integer);
|
|
for (uint32_t j = 0; j < eM_count; ++j) {
|
|
uint32_t eM_temp = eM_temps[j];
|
|
DxbcOpMul(DxbcDest::R(eM_temp), DxbcSrc::R(eM_temp),
|
|
DxbcSrc::LF(32767.0f));
|
|
}
|
|
DxbcOpEndIf();
|
|
for (uint32_t j = 0; j < eM_count; ++j) {
|
|
DxbcDest eM_dest(DxbcDest::R(eM_temps[j]));
|
|
DxbcSrc eM_src(DxbcSrc::R(eM_temps[j]));
|
|
DxbcOpMax(eM_dest, eM_src, DxbcSrc::LF(-32767.0f));
|
|
DxbcOpMin(eM_dest, eM_src, DxbcSrc::LF(32767.0f));
|
|
}
|
|
}
|
|
DxbcOpElse();
|
|
{
|
|
DxbcOpIf(false, is_integer);
|
|
for (uint32_t j = 0; j < eM_count; ++j) {
|
|
uint32_t eM_temp = eM_temps[j];
|
|
DxbcOpMul(DxbcDest::R(eM_temp), DxbcSrc::R(eM_temp),
|
|
DxbcSrc::LF(65535.0f));
|
|
}
|
|
DxbcOpEndIf();
|
|
for (uint32_t j = 0; j < eM_count; ++j) {
|
|
DxbcDest eM_dest(DxbcDest::R(eM_temps[j]));
|
|
DxbcSrc eM_src(DxbcSrc::R(eM_temps[j]));
|
|
DxbcOpMax(eM_dest, eM_src, DxbcSrc::LF(0.0f));
|
|
DxbcOpMin(eM_dest, eM_src, DxbcSrc::LF(65535.0f));
|
|
}
|
|
}
|
|
DxbcOpEndIf();
|
|
for (uint32_t j = 0; j < eM_count; ++j) {
|
|
uint32_t eM_temp = eM_temps[j];
|
|
// Round to the nearest integer, according to the rules of handling
|
|
// integer formats in Direct3D.
|
|
DxbcOpRoundNE(DxbcDest::R(eM_temp), DxbcSrc::R(eM_temp));
|
|
DxbcOpFToI(DxbcDest::R(eM_temp), DxbcSrc::R(eM_temp));
|
|
DxbcOpBFI(DxbcDest::R(eM_temp, 0b0011), DxbcSrc::LU(16),
|
|
DxbcSrc::LU(16), DxbcSrc::R(eM_temp, 0b1101),
|
|
DxbcSrc::R(eM_temp, 0b1000));
|
|
}
|
|
DxbcOpBreak();
|
|
|
|
// k_16_16_FLOAT
|
|
DxbcOpCase(DxbcSrc::LU(uint32_t(ColorFormat::k_16_16_FLOAT)));
|
|
for (uint32_t j = 0; j < eM_count; ++j) {
|
|
uint32_t eM_temp = eM_temps[j];
|
|
DxbcOpF32ToF16(DxbcDest::R(eM_temp, 0b0011), DxbcSrc::R(eM_temp));
|
|
DxbcOpBFI(DxbcDest::R(eM_temp, 0b0001), DxbcSrc::LU(16),
|
|
DxbcSrc::LU(16), DxbcSrc::R(eM_temp, DxbcSrc::kYYYY),
|
|
DxbcSrc::R(eM_temp, DxbcSrc::kXXXX));
|
|
}
|
|
DxbcOpBreak();
|
|
|
|
// k_16_16_16_16_FLOAT
|
|
DxbcOpCase(DxbcSrc::LU(uint32_t(ColorFormat::k_16_16_16_16_FLOAT)));
|
|
DxbcOpMov(element_size_dest, DxbcSrc::LU(8));
|
|
for (uint32_t j = 0; j < eM_count; ++j) {
|
|
uint32_t eM_temp = eM_temps[j];
|
|
DxbcOpF32ToF16(DxbcDest::R(eM_temp), DxbcSrc::R(eM_temp));
|
|
DxbcOpBFI(DxbcDest::R(eM_temp, 0b0011), DxbcSrc::LU(16),
|
|
DxbcSrc::LU(16), DxbcSrc::R(eM_temp, 0b1101),
|
|
DxbcSrc::R(eM_temp, 0b1000));
|
|
}
|
|
DxbcOpBreak();
|
|
|
|
// k_32_FLOAT
|
|
// Already in the destination format, 4 bytes per element already
|
|
// selected.
|
|
|
|
// k_32_32_FLOAT
|
|
DxbcOpCase(DxbcSrc::LU(uint32_t(ColorFormat::k_32_32_FLOAT)));
|
|
DxbcOpMov(element_size_dest, DxbcSrc::LU(8));
|
|
// Already in the destination format.
|
|
DxbcOpBreak();
|
|
|
|
// k_32_32_32_32_FLOAT
|
|
DxbcOpCase(DxbcSrc::LU(uint32_t(ColorFormat::k_32_32_32_32_FLOAT)));
|
|
DxbcOpMov(element_size_dest, DxbcSrc::LU(16));
|
|
// Already in the destination format.
|
|
DxbcOpBreak();
|
|
}
|
|
DxbcOpEndSwitch();
|
|
// control_temp.yz are now free.
|
|
|
|
// Do endian swap.
|
|
{
|
|
DxbcDest endian_dest(DxbcDest::R(control_temp, 0b0010));
|
|
DxbcSrc endian_src(DxbcSrc::R(control_temp, DxbcSrc::kYYYY));
|
|
// Extract endianness into control_temp.y.
|
|
DxbcOpAnd(endian_dest, DxbcSrc::R(eA_temp, DxbcSrc::kZZZZ),
|
|
DxbcSrc::LU(0b111));
|
|
|
|
// Change 8-in-64 and 8-in-128 to 8-in-32.
|
|
for (uint32_t j = 0; j < 2; ++j) {
|
|
DxbcOpIEq(
|
|
DxbcDest::R(control_temp, 0b0100), endian_src,
|
|
DxbcSrc::LU(uint32_t(j ? Endian128::k8in128 : Endian128::k8in64)));
|
|
for (uint32_t k = 0; k < eM_count; ++k) {
|
|
uint32_t eM_temp = eM_temps[k];
|
|
DxbcOpMovC(DxbcDest::R(eM_temp),
|
|
DxbcSrc::R(control_temp, DxbcSrc::kZZZZ),
|
|
DxbcSrc::R(eM_temp, j ? 0b00011011 : 0b10110001),
|
|
DxbcSrc::R(eM_temp));
|
|
}
|
|
DxbcOpMovC(endian_dest, DxbcSrc::R(control_temp, DxbcSrc::kZZZZ),
|
|
DxbcSrc::LU(uint32_t(Endian128::k8in32)), endian_src);
|
|
}
|
|
|
|
uint32_t swap_temp = PushSystemTemp();
|
|
DxbcDest swap_temp_dest(DxbcDest::R(swap_temp));
|
|
DxbcSrc swap_temp_src(DxbcSrc::R(swap_temp));
|
|
|
|
// 8-in-16 or one half of 8-in-32.
|
|
DxbcOpSwitch(endian_src);
|
|
DxbcOpCase(DxbcSrc::LU(uint32_t(Endian128::k8in16)));
|
|
DxbcOpCase(DxbcSrc::LU(uint32_t(Endian128::k8in32)));
|
|
for (uint32_t j = 0; j < eM_count; ++j) {
|
|
DxbcDest eM_dest(DxbcDest::R(eM_temps[j]));
|
|
DxbcSrc eM_src(DxbcSrc::R(eM_temps[j]));
|
|
// Temp = X0Z0.
|
|
DxbcOpAnd(swap_temp_dest, eM_src, DxbcSrc::LU(0x00FF00FF));
|
|
// eM = YZW0.
|
|
DxbcOpUShR(eM_dest, eM_src, DxbcSrc::LU(8));
|
|
// eM = Y0W0.
|
|
DxbcOpAnd(eM_dest, eM_src, DxbcSrc::LU(0x00FF00FF));
|
|
// eM = YXWZ.
|
|
DxbcOpUMAd(eM_dest, swap_temp_src, DxbcSrc::LU(256), eM_src);
|
|
}
|
|
DxbcOpBreak();
|
|
DxbcOpEndSwitch();
|
|
|
|
// 16-in-32 or another half of 8-in-32.
|
|
DxbcOpSwitch(endian_src);
|
|
DxbcOpCase(DxbcSrc::LU(uint32_t(Endian128::k8in32)));
|
|
DxbcOpCase(DxbcSrc::LU(uint32_t(Endian128::k16in32)));
|
|
for (uint32_t j = 0; j < eM_count; ++j) {
|
|
DxbcDest eM_dest(DxbcDest::R(eM_temps[j]));
|
|
DxbcSrc eM_src(DxbcSrc::R(eM_temps[j]));
|
|
// Temp = ZW00.
|
|
DxbcOpUShR(swap_temp_dest, eM_src, DxbcSrc::LU(16));
|
|
// eM = ZWXY.
|
|
DxbcOpBFI(eM_dest, DxbcSrc::LU(16), DxbcSrc::LU(16), eM_src,
|
|
swap_temp_src);
|
|
}
|
|
DxbcOpBreak();
|
|
DxbcOpEndSwitch();
|
|
|
|
// Release swap_temp.
|
|
PopSystemTemp();
|
|
}
|
|
// control_temp.yz are now free.
|
|
|
|
DxbcDest address_dest(DxbcDest::R(eA_temp, 0b0001));
|
|
DxbcSrc address_src(DxbcSrc::R(eA_temp, DxbcSrc::kXXXX));
|
|
// Multiply the base address by dword size, also dropping the 0x40000000
|
|
// bit.
|
|
DxbcOpIShL(address_dest, address_src, DxbcSrc::LU(2));
|
|
// Drop the exponent in the element index.
|
|
DxbcOpAnd(DxbcDest::R(eA_temp, 0b0010), DxbcSrc::R(eA_temp, DxbcSrc::kYYYY),
|
|
DxbcSrc::LU((1 << 23) - 1));
|
|
// Add the offset of the first written element to the base address.
|
|
DxbcOpUMAd(address_dest, DxbcSrc::R(eA_temp, DxbcSrc::kYYYY),
|
|
element_size_src, address_src);
|
|
// Do the writes.
|
|
DxbcSrc eM_written_src(
|
|
DxbcSrc::R(system_temp_memexport_written_).Select(i >> 2));
|
|
uint32_t eM_written_base = 1u << ((i & 3) << 3);
|
|
for (uint32_t j = 0; j < eM_count; ++j) {
|
|
// Go to the next eM#.
|
|
uint32_t eM_relative_offset = eM_offsets[j] - (j ? eM_offsets[j - 1] : 0);
|
|
if (eM_relative_offset) {
|
|
if (eM_relative_offset == 1) {
|
|
DxbcOpIAdd(address_dest, element_size_src, address_src);
|
|
} else {
|
|
DxbcOpUMAd(address_dest, DxbcSrc::LU(eM_relative_offset),
|
|
element_size_src, address_src);
|
|
}
|
|
}
|
|
// Check if the eM# was actually written to on the execution path.
|
|
DxbcOpAnd(DxbcDest::R(control_temp, 0b0010), eM_written_src,
|
|
DxbcSrc::LU(eM_written_base << eM_offsets[j]));
|
|
DxbcOpIf(true, DxbcSrc::R(control_temp, DxbcSrc::kYYYY));
|
|
// Write the element of the needed size.
|
|
DxbcSrc eM_src(DxbcSrc::R(eM_temps[j]));
|
|
DxbcOpSwitch(element_size_src);
|
|
for (uint32_t k = 1; k <= 4; k <<= 1) {
|
|
DxbcOpCase(DxbcSrc::LU(k * 4));
|
|
DxbcOpStoreRaw(
|
|
DxbcDest::U(0, uint32_t(UAVRegister::kSharedMemory), (1 << k) - 1),
|
|
address_src, eM_src);
|
|
DxbcOpBreak();
|
|
}
|
|
DxbcOpEndSwitch();
|
|
DxbcOpEndIf();
|
|
}
|
|
// control_temp.y is now free.
|
|
}
|
|
|
|
// Close the memexport possibility check.
|
|
DxbcOpEndIf();
|
|
|
|
// Release control_temp.
|
|
PopSystemTemp();
|
|
}
|
|
|
|
} // namespace gpu
|
|
} // namespace xe
|