1444 lines
49 KiB
C++
1444 lines
49 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/hlsl_shader_translator.h"
|
|
|
|
#include <algorithm>
|
|
|
|
#include "xenia/base/assert.h"
|
|
|
|
namespace xe {
|
|
namespace gpu {
|
|
using namespace ucode;
|
|
|
|
constexpr uint32_t kMaxInterpolators = 16;
|
|
|
|
#define EmitSource(...) source_inner_.AppendFormat(__VA_ARGS__)
|
|
#define EmitSourceDepth(...) \
|
|
source_inner_.Append(depth_prefix_); \
|
|
source_inner_.AppendFormat(__VA_ARGS__)
|
|
|
|
HlslShaderTranslator::HlslShaderTranslator() {}
|
|
HlslShaderTranslator::~HlslShaderTranslator() = default;
|
|
|
|
void HlslShaderTranslator::Reset() {
|
|
ShaderTranslator::Reset();
|
|
|
|
source_inner_.Reset();
|
|
depth_ = 0;
|
|
depth_prefix_[0] = 0;
|
|
|
|
cf_wrote_pc_ = false;
|
|
cf_exec_pred_ = false;
|
|
cf_exec_pred_cond_ = false;
|
|
|
|
writes_depth_ = false;
|
|
|
|
srv_bindings_.clear();
|
|
|
|
sampler_count_ = 0;
|
|
|
|
cube_used_ = false;
|
|
}
|
|
|
|
void HlslShaderTranslator::EmitTranslationError(const char* message) {
|
|
ShaderTranslator::EmitTranslationError(message);
|
|
EmitSourceDepth("// TRANSLATION ERROR: %s\n", message);
|
|
}
|
|
|
|
void HlslShaderTranslator::EmitUnimplementedTranslationError() {
|
|
ShaderTranslator::EmitUnimplementedTranslationError();
|
|
EmitSourceDepth("// UNIMPLEMENTED TRANSLATION\n");
|
|
}
|
|
|
|
void HlslShaderTranslator::Indent() {
|
|
depth_prefix_[depth_] = ' ';
|
|
depth_prefix_[depth_ + 1] = ' ';
|
|
depth_prefix_[depth_ + 2] = 0;
|
|
depth_ += 2;
|
|
}
|
|
|
|
void HlslShaderTranslator::Unindent() {
|
|
depth_ -= 2;
|
|
depth_prefix_[depth_] = 0;
|
|
}
|
|
|
|
void HlslShaderTranslator::StartTranslation() {
|
|
// Main function level (1).
|
|
Indent();
|
|
// Do while PC != 0xFFFF level (2).
|
|
Indent();
|
|
// Switch level (3).
|
|
Indent();
|
|
EmitSourceDepth("case 0u:\n");
|
|
}
|
|
|
|
std::vector<uint8_t> HlslShaderTranslator::CompleteTranslation() {
|
|
// Add the declarations, the prologue and the epilogue knowing what is needed.
|
|
StringBuffer source;
|
|
|
|
// Common preprocessor statements.
|
|
// 3557 is the "loop only executes for 1 iteration" warning caused by the
|
|
// control flow loop design.
|
|
source.Append(
|
|
"#pragma warning(disable : 3557)\n"
|
|
"\n"
|
|
"#define XE_FLT_MAX 3.402823466e+38\n"
|
|
"\n");
|
|
|
|
// Cubemap sampling. XeCubeTo2D emulates the cube vector ALU instruction that
|
|
// gives (t, s, 2 * major axis, face index), XeCubeTo3D reverts its effects
|
|
// in tfetchCube because sampling a cubemap as an array doesn't work properly
|
|
// with mipmaps (at the edges, there's a jump of S and T between 0 and 1, and
|
|
// the entire texture becomes 1x1 in size).
|
|
//
|
|
// If X is the major axis:
|
|
// T is -Y
|
|
// S is -Z for positive X, +Z for negative X
|
|
// Face is 0 for positive X, 1 for negative X
|
|
// If Y is the major axis:
|
|
// T is +Z for positive Y, -Z for negative Y
|
|
// S is +X
|
|
// Face is 2 for positive Y, 3 for negative Y
|
|
// If Z is the major axis:
|
|
// T is -Y
|
|
// S is +X for positive Z, -X for negative Z
|
|
// Face is 4 for positive Z, 5 for negative Z
|
|
// From T and S, abs(2 * MA) needs to be subtracted also.
|
|
//
|
|
// The undo function accepts (s, t, face index).
|
|
if (cube_used_) {
|
|
source.Append(
|
|
"float4 XeCubeTo2D(float3 xe_cube_3d) {\n"
|
|
" float3 xe_cube_3d_abs = abs(xe_cube_3d);\n"
|
|
" float4 xe_cube_2d;\n"
|
|
" if (xe_cube_3d_abs.x >= xe_cube_3d_abs.y &&\n"
|
|
" xe_cube_3d_abs.x >= xe_cube_3d_abs.z) {\n"
|
|
" xe_cube_2d.xy = -xe_cube_3d.yz;\n"
|
|
" xe_cube_2d.y *= sign(xe_cube_3d.x);\n"
|
|
" xe_cube_2d.z = xe_cube_3d.x;\n"
|
|
" xe_cube_2d.w = 0.0;\n"
|
|
" } else if (xe_cube_3d_abs.y >= xe_cube_3d_abs.z) {\n"
|
|
" xe_cube_2d.xyz = xe_cube_3d.zxy;\n"
|
|
" xe_cube_2d.x *= sign(xe_cube_3d.y);\n"
|
|
" xe_cube_2d.w = 2.0;\n"
|
|
" } else {\n"
|
|
" xe_cube_2d.x = -xe_cube_3d.y;\n"
|
|
" xe_cube_2d.yz = xe_cube_3d.xz;\n"
|
|
" xe_cube_2d.y *= sign(xe_cube_3d.z);\n"
|
|
" xe_cube_2d.w = 4.0;\n"
|
|
" }\n"
|
|
" xe_cube_2d.w += saturate(-sign(xe_cube_2d.y));\n"
|
|
" xe_cube_2d.z *= 2.0;\n"
|
|
" xe_cube_2d.xy -= abs(xe_cube_2d.zz);\n"
|
|
" return xe_cube_2d;\n"
|
|
"}\n"
|
|
"\n"
|
|
"float3 XeCubeTo3D(float3 xe_cube_2d) {\n"
|
|
" xe_cube_2d.xy = (xe_cube_2d.xy * 2.0) + 1.0;\n"
|
|
" float3 xe_cube_3d;\n"
|
|
" uint xe_cube_face_index = uint(xe_cube_2d.z);\n"
|
|
" float xe_cube_ma_sign =\n"
|
|
" -(float(xe_cube_face_index & 1u) * 2.0 - 1.0);\n"
|
|
" uint xe_cube_ma_index = xe_cube_face_index >> 1u;\n"
|
|
" if (xe_cube_ma_index == 0u) {\n"
|
|
" xe_cube_3d.x = xe_cube_2d.z;\n"
|
|
" xe_cube_3d.yz = -xe_cube_2d.yx;\n"
|
|
" xe_cube_3d.xz *= xe_cube_ma_sign;\n"
|
|
" } else if (xe_cube_ma_index == 1u) {\n"
|
|
" xe_cube_3d = xe_cube_2d.xzy;\n"
|
|
" xe_cube_3d.yz *= xe_cube_ma_sign;\n"
|
|
" } else {\n"
|
|
" xe_cube_3d.xz = xe_cube_2d.xz * xe_cube_ma_sign;\n"
|
|
" xe_cube_3d.y = -xe_cube_2d.y;\n"
|
|
" }\n"
|
|
" return xe_cube_3d;\n"
|
|
"}\n"
|
|
"\n");
|
|
}
|
|
|
|
// Common declarations.
|
|
// Only up to 14 constant buffers can be used on binding tiers 1 and 2.
|
|
source.Append(
|
|
"cbuffer xe_system_constants : register(b0) {\n"
|
|
" float3 xe_mul_rcp_w;\n"
|
|
" uint xe_vertex_base_index;\n"
|
|
" float3 xe_ndc_scale;\n"
|
|
" uint xe_vertex_index_endian;\n"
|
|
" float3 xe_ndc_offset;\n"
|
|
" float xe_pixel_half_pixel_offset;\n"
|
|
" float2 xe_ssaa_inv_scale;\n"
|
|
" uint xe_pixel_pos_reg;\n"
|
|
" uint xe_textures_are_3d;\n"
|
|
"};\n"
|
|
"\n"
|
|
"cbuffer xe_loop_bool_constants : register(b1) {\n"
|
|
" uint xe_bool_constants[8];\n"
|
|
" uint xe_loop_constants[32];\n"
|
|
"};\n"
|
|
"\n"
|
|
"struct XeFloatConstantPage {\n"
|
|
" float4 c[32];\n"
|
|
"};\n"
|
|
"ConstantBuffer<XeFloatConstantPage> "
|
|
"xe_float_constants[8] : register(b2);\n"
|
|
"\n");
|
|
|
|
if (is_vertex_shader()) {
|
|
// Vertex fetching, output and prologue.
|
|
// Endian register (2nd word of the fetch constant) is 00 for no swap, 01
|
|
// for 8-in-16, 10 for 8-in-32 (a combination of 8-in-16 and 16-in-32), and
|
|
// 11 for 16-in-32. This means we can check bits 0 ^ 1 to see if we need to
|
|
// do a 8-in-16 swap, and bit 1 to see if a 16-in-32 swap is needed.
|
|
// Vertex element is a temporary integer value for fetches.
|
|
// -1 point size means the geometry shader will use the global setting by
|
|
// default.
|
|
source.AppendFormat(
|
|
"cbuffer xe_vertex_fetch_constants : register(b10) {\n"
|
|
" uint2 xe_vertex_fetch[96];\n"
|
|
"};\n"
|
|
"\n"
|
|
"ByteAddressBuffer xe_shared_memory : register(t0, space1);\n"
|
|
"\n"
|
|
"#define XE_BYTE_SWAP_OVERLOAD(XeByteSwapType) \\\n"
|
|
"XeByteSwapType XeByteSwap(XeByteSwapType v, uint endian) { \\\n"
|
|
" [flatten] if (((endian ^ (endian >> 1u)) & 1u) != 0u) { \\\n"
|
|
" v = ((v & 0x00FF00FFu) << 8u) | ((v & 0xFF00FF00u) >> 8u); \\\n"
|
|
" } \\\n"
|
|
" [flatten] if ((endian & 2u) != 0u) { \\\n"
|
|
" v = (v << 16u) | (v >> 16u); \\\n"
|
|
" } \\\n"
|
|
" return v; \\\n"
|
|
"}\n"
|
|
"XE_BYTE_SWAP_OVERLOAD(uint)\n"
|
|
"XE_BYTE_SWAP_OVERLOAD(uint2)\n"
|
|
"XE_BYTE_SWAP_OVERLOAD(uint3)\n"
|
|
"XE_BYTE_SWAP_OVERLOAD(uint4)\n"
|
|
"\n"
|
|
"struct XeVertexShaderOutput {\n"
|
|
" float4 position : SV_Position;\n"
|
|
" float4 interpolators[%u] : TEXCOORD;\n"
|
|
" float point_size : PSIZE;\n"
|
|
"};\n"
|
|
"\n"
|
|
"XeVertexShaderOutput main(uint xe_vertex_index_be : SV_VertexID) {\n"
|
|
" float4 xe_r[%u];\n"
|
|
" uint xe_vertex_index =\n"
|
|
" XeByteSwap(xe_vertex_index_be, xe_vertex_index_endian) +\n"
|
|
" xe_vertex_base_index;\n"
|
|
" uint4 xe_vertex_element;\n"
|
|
" xe_r[0].r = float(xe_vertex_index);\n"
|
|
" XeVertexShaderOutput xe_output;\n"
|
|
" xe_output.position = float4(0.0, 0.0, 0.0, 1.0);\n"
|
|
" xe_output.point_size = -1.0;\n",
|
|
kMaxInterpolators, register_count());
|
|
for (uint32_t i = 0; i < kMaxInterpolators; ++i) {
|
|
source.AppendFormat(" xe_output.interpolators[%u] = (0.0).xxxx;\n", i);
|
|
}
|
|
// TODO(Triang3l): Reset interpolators to zero if really needed.
|
|
} else if (is_pixel_shader()) {
|
|
// Pixel shader inputs, outputs and prologue.
|
|
// If the shader writes to depth, it needs to define
|
|
// XE_PIXEL_SHADER_WRITES_DEPTH in the beginning of the final output.
|
|
source.AppendFormat(
|
|
"struct XePixelShaderInput {\n"
|
|
" float4 position : SV_Position;\n"
|
|
" float4 interpolators[%u] : TEXCOORD;\n"
|
|
"};\n"
|
|
"\n"
|
|
"struct XePixelShaderOutput {\n"
|
|
" float4 colors[4] : SV_Target;\n"
|
|
"%s"
|
|
"};\n"
|
|
"\n"
|
|
"XePixelShaderOutput main(XePixelShaderInput xe_input) {\n"
|
|
" float4 xe_r[%u];\n"
|
|
" XePixelShaderOutput xe_output;\n"
|
|
" xe_output.colors[0] = (0.0).xxxx;\n"
|
|
" xe_output.colors[1] = (0.0).xxxx;\n"
|
|
" xe_output.colors[2] = (0.0).xxxx;\n"
|
|
" xe_output.colors[3] = (0.0).xxxx;\n",
|
|
kMaxInterpolators, writes_depth_ ? " float depth : SV_Depth;\n" : "",
|
|
register_count());
|
|
// Initialize SV_Depth if using it.
|
|
if (writes_depth_) {
|
|
source.Append(" xe_output.depth = xe_input.position.z;\n");
|
|
}
|
|
// Copy interpolants to the first registers.
|
|
uint32_t interpolator_register_count =
|
|
std::min(register_count(), kMaxInterpolators);
|
|
for (uint32_t i = 0; i < interpolator_register_count; ++i) {
|
|
source.AppendFormat(" xe_r[%u] = xe_input.interpolators[%u];\n", i, i);
|
|
}
|
|
// TODO(Triang3l): ps_param_gen.
|
|
}
|
|
|
|
// Common main function variables and prologue.
|
|
source.Append(
|
|
// Dynamic index for source operands (mainly for float and bool constants
|
|
// since they are indexed in two parts).
|
|
" uint xe_src_index;\n"
|
|
// Sources for instructions.
|
|
" float4 xe_src0, xe_src1, xe_src2;\n"
|
|
// Previous vector result (used as a scratch).
|
|
" float4 xe_pv = float4(0.0, 0.0, 0.0, 0.0);\n"
|
|
// Previous scalar result (used for RETAIN_PREV).
|
|
" float xe_ps = 0.0;\n"
|
|
// Predicate temp, clause-local. Initially false like cf_exec_pred_cond_.
|
|
" bool xe_p0 = false;\n"
|
|
// Address register when using absolute addressing.
|
|
" int xe_a0 = 0;\n"
|
|
// Loop index stack - .x is the active loop, shifted right to yzw on push.
|
|
" int4 xe_aL = int4(0, 0, 0, 0);\n"
|
|
// Loop counter stack, .x is the active loop.
|
|
// Represents number of times remaining to loop.
|
|
" uint4 xe_loop_count = uint4(0u, 0u, 0u, 0u);\n"
|
|
// Master loop and switch for flow control.
|
|
" uint xe_pc = 0u;\n"
|
|
"\n"
|
|
" do {\n"
|
|
" switch (xe_pc) {\n");
|
|
|
|
// Translated code.
|
|
source.Append(source_inner_.GetString());
|
|
|
|
// Epilogue.
|
|
if (!cf_wrote_pc_) {
|
|
source.Append(
|
|
" xe_pc = 0xFFFFu;\n"
|
|
" break;\n");
|
|
}
|
|
source.Append(
|
|
" default:\n"
|
|
" xe_pc = 0xFFFFu;\n"
|
|
" break;\n"
|
|
" }\n"
|
|
" } while (xe_pc != 0xFFFFu);\n");
|
|
if (is_vertex_shader()) {
|
|
// Restore the original W if the shader has already taken its reciprocal,
|
|
// and restore the original XYZ if the shader has divided them by W. Also
|
|
// normalize the coordinates to the viewport if the shader has returned
|
|
// unnormalized ones (for rectangle lists, for instance) and apply the half-
|
|
// pixel offset.
|
|
source.Append(
|
|
" [flatten] if (xe_mul_rcp_w.z == 0.0) {\n"
|
|
" xe_output.position.w = rcp(xe_output.position.w);\n"
|
|
" }\n"
|
|
" xe_output.position.xyz *=\n"
|
|
" lerp((1.0).xxx, xe_output.position.www, xe_mul_rcp_w.xxy);\n"
|
|
" xe_output.position.xyz =\n"
|
|
" xe_output.position.xyz * xe_ndc_scale +\n"
|
|
" xe_ndc_offset * xe_output.position.www;\n");
|
|
}
|
|
// TODO(Triang3l): Window offset, half pixel offset, alpha test, gamma.
|
|
source.Append(
|
|
" return xe_output;\n"
|
|
"}\n");
|
|
|
|
return source.ToBytes();
|
|
}
|
|
|
|
void HlslShaderTranslator::ProcessLabel(uint32_t cf_index) {
|
|
// 0 is always added in the beginning.
|
|
if (cf_index != 0) {
|
|
if (!cf_wrote_pc_) {
|
|
EmitSourceDepth("xe_pc = %uu;\n", cf_index);
|
|
EmitSourceDepth("break;");
|
|
}
|
|
EmitSourceDepth("case %uu:\n", cf_index);
|
|
}
|
|
}
|
|
|
|
void HlslShaderTranslator::ProcessControlFlowNopInstruction(uint32_t cf_index) {
|
|
EmitSourceDepth("// cnop\n");
|
|
}
|
|
|
|
void HlslShaderTranslator::ProcessControlFlowInstructionBegin(
|
|
uint32_t cf_index) {
|
|
cf_wrote_pc_ = false;
|
|
}
|
|
|
|
void HlslShaderTranslator::ProcessControlFlowInstructionEnd(uint32_t cf_index) {
|
|
if (!cf_wrote_pc_) {
|
|
EmitSourceDepth("// Falling through to L%u\n", cf_index + 1);
|
|
}
|
|
}
|
|
|
|
void HlslShaderTranslator::ProcessExecInstructionBegin(
|
|
const ParsedExecInstruction& instr) {
|
|
EmitSourceDepth("// ");
|
|
instr.Disassemble(&source_inner_);
|
|
|
|
cf_exec_pred_ = false;
|
|
switch (instr.type) {
|
|
case ParsedExecInstruction::Type::kUnconditional:
|
|
EmitSourceDepth("{\n");
|
|
break;
|
|
case ParsedExecInstruction::Type::kConditional:
|
|
EmitSourceDepth("if ((xe_bool_constants[%u] & (1u << %uu)) %c= 0u) {\n",
|
|
instr.bool_constant_index >> 5,
|
|
instr.bool_constant_index & 31,
|
|
instr.condition ? '!' : '=');
|
|
break;
|
|
case ParsedExecInstruction::Type::kPredicated:
|
|
cf_exec_pred_ = true;
|
|
cf_exec_pred_cond_ = instr.condition;
|
|
EmitSourceDepth("if (%cxe_p0) {\n", instr.condition ? ' ' : '!');
|
|
break;
|
|
}
|
|
Indent();
|
|
}
|
|
|
|
void HlslShaderTranslator::ProcessExecInstructionEnd(
|
|
const ParsedExecInstruction& instr) {
|
|
if (instr.is_end) {
|
|
EmitSourceDepth("xe_pc = 0xFFFFu;\n");
|
|
EmitSourceDepth("break;\n");
|
|
cf_wrote_pc_ = true;
|
|
}
|
|
Unindent();
|
|
EmitSourceDepth("}\n");
|
|
}
|
|
|
|
void HlslShaderTranslator::ProcessLoopStartInstruction(
|
|
const ParsedLoopStartInstruction& instr) {
|
|
EmitSourceDepth("// ");
|
|
instr.Disassemble(&source_inner_);
|
|
|
|
// Setup counter.
|
|
EmitSourceDepth("xe_loop_count.yzw = xe_loop_count.xyz;\n");
|
|
EmitSourceDepth("xe_loop_count.x = xe_loop_constants[%u] & 0xFFu;\n",
|
|
instr.loop_constant_index);
|
|
|
|
// Setup relative indexing.
|
|
EmitSourceDepth("xe_aL = xe_aL.xxyz;\n");
|
|
if (!instr.is_repeat) {
|
|
// Push new loop starting index if not reusing the current one.
|
|
EmitSourceDepth("xe_aL.x = int((xe_loop_constants[%u] >> 8u) & 0xFFu);\n",
|
|
instr.loop_constant_index);
|
|
}
|
|
|
|
// Quick skip loop if zero count.
|
|
EmitSourceDepth("if (xe_loop_count.x == 0u) {\n");
|
|
EmitSourceDepth(" xe_pc = %uu; // Skip loop to L%u\n",
|
|
instr.loop_skip_address, instr.loop_skip_address);
|
|
EmitSourceDepth("} else {\n");
|
|
EmitSourceDepth(" xe_pc = %uu; // Fallthrough to loop body L%u\n",
|
|
instr.dword_index + 1, instr.dword_index + 1);
|
|
EmitSourceDepth("}\n");
|
|
EmitSourceDepth("break;\n");
|
|
cf_wrote_pc_ = true;
|
|
}
|
|
|
|
void HlslShaderTranslator::ProcessLoopEndInstruction(
|
|
const ParsedLoopEndInstruction& instr) {
|
|
EmitSourceDepth("// ");
|
|
instr.Disassemble(&source_inner_);
|
|
|
|
// Decrement loop counter, and if we are done break out.
|
|
EmitSourceDepth("if (--xe_loop_count.x == 0u");
|
|
if (instr.is_predicated_break) {
|
|
// If the predicate condition is met we 'break;' out of the loop.
|
|
// Need to restore stack and fall through to the next cf.
|
|
EmitSource(" || %cxe_p0) {\n", instr.predicate_condition ? ' ' : '!');
|
|
} else {
|
|
EmitSource(") {\n");
|
|
}
|
|
Indent();
|
|
|
|
// Loop completed - pop and fall through to next cf.
|
|
EmitSourceDepth("xe_loop_count.xyz = xe_loop_count.yzw;\n");
|
|
EmitSourceDepth("xe_loop_count.w = 0u;\n");
|
|
EmitSourceDepth("xe_aL.xyz = xe_aL.yzw;\n");
|
|
EmitSourceDepth("xe_aL.w = 0;\n");
|
|
EmitSourceDepth("xe_pc = %uu; // Exit loop to L%u\n", instr.dword_index + 1,
|
|
instr.dword_index + 1);
|
|
|
|
Unindent();
|
|
EmitSourceDepth("} else {\n");
|
|
Indent();
|
|
|
|
// Still looping. Adjust index and jump back to body.
|
|
EmitSourceDepth("xe_aL.x += int(xe_loop_constants[%u] << 8u) >> 24;\n",
|
|
instr.loop_constant_index);
|
|
EmitSourceDepth("xe_pc = %uu; // Loop back to body L%u\n",
|
|
instr.loop_body_address, instr.loop_body_address);
|
|
|
|
Unindent();
|
|
EmitSourceDepth("}\n");
|
|
EmitSourceDepth("break;\n");
|
|
cf_wrote_pc_ = true;
|
|
}
|
|
|
|
void HlslShaderTranslator::ProcessCallInstruction(
|
|
const ParsedCallInstruction& instr) {
|
|
EmitSourceDepth("// ");
|
|
instr.Disassemble(&source_inner_);
|
|
|
|
EmitUnimplementedTranslationError();
|
|
}
|
|
|
|
void HlslShaderTranslator::ProcessReturnInstruction(
|
|
const ParsedReturnInstruction& instr) {
|
|
EmitSourceDepth("// ");
|
|
instr.Disassemble(&source_inner_);
|
|
|
|
EmitUnimplementedTranslationError();
|
|
}
|
|
|
|
void HlslShaderTranslator::ProcessJumpInstruction(
|
|
const ParsedJumpInstruction& instr) {
|
|
EmitSourceDepth("// ");
|
|
instr.Disassemble(&source_inner_);
|
|
|
|
bool needs_fallthrough = false;
|
|
switch (instr.type) {
|
|
case ParsedJumpInstruction::Type::kUnconditional:
|
|
EmitSourceDepth("{\n");
|
|
break;
|
|
case ParsedJumpInstruction::Type::kConditional:
|
|
EmitSourceDepth("if ((xe_bool_constants[%u] & (1u << %uu)) %c= 0u) {\n",
|
|
instr.bool_constant_index >> 5,
|
|
instr.bool_constant_index & 31,
|
|
instr.condition ? '!' : '=');
|
|
needs_fallthrough = true;
|
|
break;
|
|
case ParsedJumpInstruction::Type::kPredicated:
|
|
EmitSourceDepth("if (%cxe_p0) {\n", instr.condition ? ' ' : '!');
|
|
needs_fallthrough = true;
|
|
break;
|
|
}
|
|
Indent();
|
|
|
|
EmitSourceDepth("xe_pc = %uu; // L%u\n", instr.target_address,
|
|
instr.target_address);
|
|
EmitSourceDepth("break;\n");
|
|
|
|
Unindent();
|
|
if (needs_fallthrough) {
|
|
uint32_t next_address = instr.dword_index + 1;
|
|
EmitSourceDepth("} else {\n");
|
|
EmitSourceDepth(" xe_pc = %uu; // Fallthrough to L%u\n", next_address,
|
|
next_address);
|
|
}
|
|
EmitSourceDepth("}\n");
|
|
}
|
|
|
|
void HlslShaderTranslator::ProcessAllocInstruction(
|
|
const ParsedAllocInstruction& instr) {
|
|
EmitSourceDepth("// ");
|
|
instr.Disassemble(&source_inner_);
|
|
}
|
|
|
|
bool HlslShaderTranslator::BeginPredicatedInstruction(
|
|
bool is_predicated, bool predicate_condition) {
|
|
if (is_predicated &&
|
|
(!cf_exec_pred_ || cf_exec_pred_cond_ != predicate_condition)) {
|
|
EmitSourceDepth("if (%cxe_p0) {\n", predicate_condition ? ' ' : '!');
|
|
Indent();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void HlslShaderTranslator::EndPredicatedInstruction(bool conditional_emitted) {
|
|
if (conditional_emitted) {
|
|
Unindent();
|
|
EmitSourceDepth("}\n");
|
|
}
|
|
}
|
|
|
|
void HlslShaderTranslator::EmitLoadOperand(size_t src_index,
|
|
const InstructionOperand& op) {
|
|
// If indexing dynamically, emit the index because float and bool constants
|
|
// need to be indexed in two parts.
|
|
// Also verify we are not using vertex/texture fetch constants here.
|
|
uint32_t storage_index_max;
|
|
switch (op.storage_source) {
|
|
case InstructionStorageSource::kRegister:
|
|
storage_index_max = 127;
|
|
break;
|
|
case InstructionStorageSource::kConstantFloat:
|
|
case InstructionStorageSource::kConstantBool:
|
|
storage_index_max = 255;
|
|
break;
|
|
case InstructionStorageSource::kConstantInt:
|
|
storage_index_max = 31;
|
|
break;
|
|
default:
|
|
assert_always();
|
|
return;
|
|
}
|
|
if (op.storage_addressing_mode ==
|
|
InstructionStorageAddressingMode::kAddressAbsolute) {
|
|
EmitSourceDepth("xe_src_index = uint(%u + xe_a0) & %uu;\n",
|
|
op.storage_index, storage_index_max);
|
|
} else if (op.storage_addressing_mode ==
|
|
InstructionStorageAddressingMode::kAddressRelative) {
|
|
EmitSourceDepth("xe_src_index = uint(%u + xe_aL.x) & %uu;\n",
|
|
op.storage_index, storage_index_max);
|
|
}
|
|
|
|
// Negation and abs are store modifiers, so they're applied after swizzling.
|
|
EmitSourceDepth("xe_src%u = ", uint32_t(src_index));
|
|
if (op.is_negated) {
|
|
EmitSource("-");
|
|
}
|
|
if (op.is_absolute_value) {
|
|
EmitSource("abs");
|
|
}
|
|
EmitSource("(");
|
|
|
|
if (op.storage_addressing_mode == InstructionStorageAddressingMode::kStatic) {
|
|
switch (op.storage_source) {
|
|
case InstructionStorageSource::kRegister:
|
|
EmitSource("xe_r[%u]", op.storage_index);
|
|
break;
|
|
case InstructionStorageSource::kConstantFloat:
|
|
EmitSource("xe_float_constants[%u].c[%u]", op.storage_index >> 5,
|
|
op.storage_index & 31);
|
|
break;
|
|
case InstructionStorageSource::kConstantInt:
|
|
EmitSource("xe_loop_constants[%u]", op.storage_index);
|
|
break;
|
|
case InstructionStorageSource::kConstantBool:
|
|
EmitSource("float((xe_bool_constants[%u] >> %uu) & 1u)",
|
|
op.storage_index >> 5, op.storage_index & 31);
|
|
break;
|
|
default:
|
|
assert_always();
|
|
break;
|
|
}
|
|
} else {
|
|
switch (op.storage_source) {
|
|
case InstructionStorageSource::kRegister:
|
|
EmitSource("xe_r[xe_src_index]");
|
|
break;
|
|
case InstructionStorageSource::kConstantFloat:
|
|
EmitSource(
|
|
"xe_float_constants[xe_src_index >> 5u].c[xe_src_index & 31u]");
|
|
break;
|
|
case InstructionStorageSource::kConstantInt:
|
|
EmitSource("xe_loop_constants[xe_src_index]");
|
|
break;
|
|
case InstructionStorageSource::kConstantBool:
|
|
EmitSource("float((xe_bool_constants[xe_src_index >> 5u] >> "
|
|
"(xe_src_index & 31u)) & 1u)");
|
|
break;
|
|
default:
|
|
assert_always();
|
|
break;
|
|
}
|
|
}
|
|
|
|
EmitSource(")");
|
|
// Integer and bool constants are scalar, can't swizzle them.
|
|
if (op.storage_source == InstructionStorageSource::kConstantInt ||
|
|
op.storage_source == InstructionStorageSource::kConstantBool) {
|
|
EmitSource(".xxxx");
|
|
} else {
|
|
if (!op.is_standard_swizzle()) {
|
|
EmitSource(".");
|
|
// For 1 component stores it will be .aaaa, for 2 components it's .abbb.
|
|
for (int i = 0; i < op.component_count; ++i) {
|
|
EmitSource("%c", GetCharForSwizzle(op.components[i]));
|
|
}
|
|
for (int i = op.component_count; i < 4; ++i) {
|
|
EmitSource("%c",
|
|
GetCharForSwizzle(op.components[op.component_count - 1]));
|
|
}
|
|
}
|
|
}
|
|
EmitSource(";\n");
|
|
}
|
|
|
|
void HlslShaderTranslator::EmitStoreResult(const InstructionResult& result,
|
|
bool source_is_scalar) {
|
|
bool storage_is_scalar =
|
|
result.storage_target == InstructionStorageTarget::kPointSize ||
|
|
result.storage_target == InstructionStorageTarget::kDepth;
|
|
if (storage_is_scalar) {
|
|
if (!result.write_mask[0]) {
|
|
return;
|
|
}
|
|
} else {
|
|
if (!result.has_any_writes()) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
bool storage_is_array = false;
|
|
switch (result.storage_target) {
|
|
case InstructionStorageTarget::kRegister:
|
|
EmitSourceDepth("xe_r");
|
|
storage_is_array = true;
|
|
break;
|
|
case InstructionStorageTarget::kInterpolant:
|
|
EmitSourceDepth("xe_output.interpolators");
|
|
storage_is_array = true;
|
|
break;
|
|
case InstructionStorageTarget::kPosition:
|
|
EmitSourceDepth("xe_output.position");
|
|
break;
|
|
case InstructionStorageTarget::kPointSize:
|
|
EmitSourceDepth("xe_output.point_size");
|
|
break;
|
|
case InstructionStorageTarget::kColorTarget:
|
|
EmitSourceDepth("xe_output.colors");
|
|
storage_is_array = true;
|
|
break;
|
|
case InstructionStorageTarget::kDepth:
|
|
EmitSourceDepth("xe_output.depth");
|
|
writes_depth_ = true;
|
|
break;
|
|
default:
|
|
case InstructionStorageTarget::kNone:
|
|
return;
|
|
}
|
|
if (storage_is_array) {
|
|
switch (result.storage_addressing_mode) {
|
|
case InstructionStorageAddressingMode::kStatic:
|
|
EmitSource("[%u]", result.storage_index);
|
|
break;
|
|
case InstructionStorageAddressingMode::kAddressAbsolute:
|
|
EmitSource("[%u + xe_a0]", result.storage_index);
|
|
break;
|
|
case InstructionStorageAddressingMode::kAddressRelative:
|
|
EmitSource("[%u + xe_aL.x]", result.storage_index);
|
|
break;
|
|
}
|
|
}
|
|
if (storage_is_scalar) {
|
|
EmitSource(" = ");
|
|
switch (result.components[0]) {
|
|
case SwizzleSource::k0:
|
|
EmitSource("0.0");
|
|
break;
|
|
case SwizzleSource::k1:
|
|
EmitSource("1.0");
|
|
break;
|
|
default:
|
|
if (result.is_clamped) {
|
|
EmitSource("saturate(");
|
|
}
|
|
if (source_is_scalar) {
|
|
EmitSource("xe_ps");
|
|
} else {
|
|
EmitSource("xe_pv.%c", GetCharForSwizzle(result.components[0]));
|
|
}
|
|
if (result.is_clamped) {
|
|
EmitSource(")");
|
|
}
|
|
break;
|
|
}
|
|
} else {
|
|
bool has_const_writes = false;
|
|
uint32_t component_write_count = 0;
|
|
EmitSource(".");
|
|
for (uint32_t i = 0; i < 4; ++i) {
|
|
if (result.write_mask[i]) {
|
|
if (result.components[i] == SwizzleSource::k0 ||
|
|
result.components[i] == SwizzleSource::k1) {
|
|
has_const_writes = true;
|
|
}
|
|
++component_write_count;
|
|
EmitSource("%c", GetCharForSwizzle(GetSwizzleFromComponentIndex(i)));
|
|
}
|
|
}
|
|
EmitSource(" = ");
|
|
if (result.is_clamped) {
|
|
EmitSource("saturate(");
|
|
}
|
|
if (has_const_writes) {
|
|
if (component_write_count > 1) {
|
|
EmitSource("float%u(", component_write_count);
|
|
}
|
|
bool has_written = false;
|
|
for (uint32_t i = 0; i < 4; ++i) {
|
|
if (result.write_mask[i]) {
|
|
if (has_written) {
|
|
EmitSource(", ");
|
|
}
|
|
has_written = true;
|
|
switch (result.components[i]) {
|
|
case SwizzleSource::k0:
|
|
EmitSource("0.0");
|
|
break;
|
|
case SwizzleSource::k1:
|
|
EmitSource("1.0");
|
|
break;
|
|
default:
|
|
if (source_is_scalar) {
|
|
EmitSource("xe_ps");
|
|
} else {
|
|
EmitSource("xe_pv.%c", GetCharForSwizzle(result.components[i]));
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (component_write_count > 1) {
|
|
EmitSource(")");
|
|
}
|
|
} else {
|
|
if (source_is_scalar) {
|
|
EmitSource("xe_ps");
|
|
if (component_write_count > 1) {
|
|
EmitSource(".x");
|
|
if (component_write_count > 2) {
|
|
EmitSource("x");
|
|
if (component_write_count > 3) {
|
|
EmitSource("x");
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
EmitSource("xe_pv.");
|
|
for (uint32_t i = 0; i < 4; ++i) {
|
|
if (result.write_mask[i]) {
|
|
EmitSource("%c", GetCharForSwizzle(result.components[i]));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (result.is_clamped) {
|
|
EmitSource(")");
|
|
}
|
|
}
|
|
EmitSource(";\n");
|
|
}
|
|
|
|
void HlslShaderTranslator::ProcessVertexFetchInstruction(
|
|
const ParsedVertexFetchInstruction& instr) {
|
|
EmitSourceDepth("// ");
|
|
instr.Disassemble(&source_inner_);
|
|
|
|
if (instr.operand_count < 2 ||
|
|
instr.operands[1].storage_source !=
|
|
InstructionStorageSource::kVertexFetchConstant) {
|
|
assert_always();
|
|
return;
|
|
}
|
|
|
|
bool conditional_emitted = BeginPredicatedInstruction(
|
|
instr.is_predicated, instr.predicate_condition);
|
|
|
|
// Load the element from the shared memory as uints and swap.
|
|
EmitLoadOperand(0, instr.operands[0]);
|
|
const char* load_swizzle;
|
|
const char* load_function_suffix;
|
|
switch (instr.attributes.data_format) {
|
|
case VertexFormat::k_16_16_16_16:
|
|
case VertexFormat::k_16_16_16_16_FLOAT:
|
|
case VertexFormat::k_32_32:
|
|
case VertexFormat::k_32_32_FLOAT:
|
|
load_swizzle = ".xy";
|
|
load_function_suffix = "2";
|
|
break;
|
|
case VertexFormat::k_32_32_32_FLOAT:
|
|
load_swizzle = ".xyz";
|
|
load_function_suffix = "3";
|
|
break;
|
|
case VertexFormat::k_32_32_32_32:
|
|
case VertexFormat::k_32_32_32_32_FLOAT:
|
|
load_swizzle = "";
|
|
load_function_suffix = "4";
|
|
break;
|
|
default:
|
|
load_swizzle = ".x";
|
|
load_function_suffix = "";
|
|
break;
|
|
}
|
|
EmitSourceDepth("xe_vertex_element%s = XeByteSwap(xe_shared_memory.Load%s(\n",
|
|
load_swizzle, load_function_suffix);
|
|
EmitSourceDepth(" ((xe_vertex_fetch[%uu].x << 2u) & 0x1FFFFFFCu)",
|
|
instr.operands[1].storage_index);
|
|
if (instr.attributes.stride != 0) {
|
|
EmitSource(" + uint(xe_src0.x) * %uu", instr.attributes.stride * 4);
|
|
}
|
|
if (instr.attributes.offset != 0) {
|
|
EmitSource(" + %uu", instr.attributes.offset * 4);
|
|
}
|
|
EmitSource("),\n");
|
|
EmitSourceDepth(" xe_vertex_fetch[%u].y);\n",
|
|
instr.operands[1].storage_index);
|
|
|
|
// Convert to the target format.
|
|
switch (instr.attributes.data_format) {
|
|
case VertexFormat::k_8_8_8_8:
|
|
EmitSourceDepth("xe_vertex_element = (xe_vertex_element.xxxx >>\n");
|
|
EmitSourceDepth(" uint4(0u, 8u, 16u, 24u)) & 255u;\n");
|
|
if (instr.attributes.is_signed) {
|
|
EmitSourceDepth(
|
|
"xe_pv = float4(int4(xe_vertex_element << 24u) >> 24);\n");
|
|
} else {
|
|
EmitSourceDepth("xe_pv = float4(xe_vertex_element);\n");
|
|
}
|
|
if (!instr.attributes.is_integer) {
|
|
if (instr.attributes.is_signed) {
|
|
EmitSourceDepth("xe_pv = max(xe_pv * (1.0 / 127.0), (-1.0).xxxx);\n");
|
|
} else {
|
|
EmitSourceDepth("xe_pv *= 1.0 / 255.0;\n");
|
|
}
|
|
}
|
|
break;
|
|
case VertexFormat::k_2_10_10_10:
|
|
EmitSourceDepth("xe_vertex_element = (xe_vertex_element.xxxx >>\n");
|
|
EmitSourceDepth(
|
|
" uint4(0u, 10u, 20u, 30u)) & uint4((1023u).xxx, 3u);\n");
|
|
if (instr.attributes.is_signed) {
|
|
EmitSourceDepth(
|
|
"xe_pv = float4(int4(xe_vertex_element << uint4((22u).xxx, 3u))\n");
|
|
EmitSourceDepth(" >> int4((22).xxx, 3));\n");
|
|
} else {
|
|
EmitSourceDepth("xe_pv = float4(xe_vertex_element);\n");
|
|
}
|
|
if (!instr.attributes.is_integer) {
|
|
if (instr.attributes.is_signed) {
|
|
EmitSourceDepth("xe_pv = max(xe_pv * float4((1.0 / 511.0).xxx, 1.0), "
|
|
"(-1.0).xxxx);\n");
|
|
} else {
|
|
EmitSourceDepth("xe_pv *= float4((1.0 / 1023.0).xxx, 1.0 / 3.0);\n");
|
|
}
|
|
}
|
|
break;
|
|
case VertexFormat::k_10_11_11:
|
|
EmitSourceDepth("xe_vertex_element.xyz = (xe_vertex_element.xxx >>\n");
|
|
EmitSourceDepth(
|
|
" uint3(0u, 11u, 22u)) & uint3(2047u, 2047u, 1023u);\n");
|
|
if (instr.attributes.is_signed) {
|
|
EmitSourceDepth("xe_pv.xyz = float3(int3(xe_vertex_element.xyz <<\n");
|
|
EmitSourceDepth(" uint3(21u, 21u, 22u)) >> int3(21, 21, 22));\n");
|
|
} else {
|
|
EmitSourceDepth("xe_pv.xyz = float3(xe_vertex_element.xyz);\n");
|
|
}
|
|
if (!instr.attributes.is_integer) {
|
|
if (instr.attributes.is_signed) {
|
|
EmitSourceDepth("xe_pv.xyz = max(xe_pv.xyz *\n");
|
|
EmitSourceDepth(
|
|
" float3((1.0 / 1023.0).xx, 1.0 / 511.0), (-1.0).xxx);\n");
|
|
} else {
|
|
EmitSourceDepth(
|
|
"xe_pv.xyz *= float3((1.0 / 2047.0).xx, 1.0 / 1023.0);\n");
|
|
}
|
|
}
|
|
EmitSourceDepth("xe_pv.w = 1.0;\n");
|
|
break;
|
|
case VertexFormat::k_11_11_10:
|
|
EmitSourceDepth("xe_vertex_element.xyz = (xe_vertex_element.xxx >>\n");
|
|
EmitSourceDepth(
|
|
" uint3(0u, 10u, 21u)) & uint3(1023u, 2047u, 2047u);\n");
|
|
if (instr.attributes.is_signed) {
|
|
EmitSourceDepth("xe_pv.xyz = float3(int3(xe_vertex_element.xyz <<\n");
|
|
EmitSourceDepth(" uint3(22u, 21u, 21u)) >> int3(22, 21, 21));\n");
|
|
} else {
|
|
EmitSourceDepth("xe_pv.xyz = float3(xe_vertex_element.xyz);\n");
|
|
}
|
|
if (!instr.attributes.is_integer) {
|
|
if (instr.attributes.is_signed) {
|
|
EmitSourceDepth("xe_pv.xyz = max(xe_pv.xyz *\n");
|
|
EmitSourceDepth(
|
|
" float3(1.0 / 511.0, (1.0 / 1023.0).xx), (-1.0).xxx);\n");
|
|
} else {
|
|
EmitSourceDepth(
|
|
"xe_pv.xyz *= float3(1.0 / 1023.0, (1.0 / 2047.0).xx);\n");
|
|
}
|
|
}
|
|
EmitSourceDepth("xe_pv.w = 1.0;\n");
|
|
break;
|
|
case VertexFormat::k_16_16:
|
|
EmitSourceDepth("xe_vertex_element.xy = (xe_vertex_element.xx >>\n");
|
|
EmitSourceDepth(" uint2(0u, 16u)) & 65535u;\n");
|
|
if (instr.attributes.is_signed) {
|
|
EmitSourceDepth(
|
|
"xe_pv.xy = float2(int2(xe_vertex_element.xy << 16u) >> 16);\n");
|
|
} else {
|
|
EmitSourceDepth("xe_pv.xy = float2(xe_vertex_element.xy);\n");
|
|
}
|
|
if (!instr.attributes.is_integer) {
|
|
if (instr.attributes.is_signed) {
|
|
EmitSourceDepth(
|
|
"xe_pv.xy = max(xe_pv.xy * (1.0 / 32767.0), (-1.0).xx);\n");
|
|
} else {
|
|
EmitSourceDepth("xe_pv.xy *= 1.0 / 65535.0;\n");
|
|
}
|
|
}
|
|
EmitSourceDepth("xe_pv.zw = float2(0.0, 1.0);\n");
|
|
break;
|
|
case VertexFormat::k_16_16_16_16:
|
|
EmitSourceDepth("xe_vertex_element = (xe_vertex_element.xxxx >>\n");
|
|
EmitSourceDepth(" uint4(0u, 16u, 0u, 16u)) & 65535u;\n");
|
|
if (instr.attributes.is_signed) {
|
|
EmitSourceDepth(
|
|
"xe_pv = float4(int4(xe_vertex_element << 16u) >> 16);\n");
|
|
} else {
|
|
EmitSourceDepth("xe_pv = float4(xe_vertex_element);\n");
|
|
}
|
|
if (!instr.attributes.is_integer) {
|
|
if (instr.attributes.is_signed) {
|
|
EmitSourceDepth(
|
|
"xe_pv = max(xe_pv * (1.0 / 32767.0), (-1.0).xxxx);\n");
|
|
} else {
|
|
EmitSourceDepth("xe_pv *= 1.0 / 65535.0;\n");
|
|
}
|
|
}
|
|
break;
|
|
case VertexFormat::k_16_16_FLOAT:
|
|
EmitSourceDepth("xe_vertex_element.xy = (xe_vertex_element.xx >>\n");
|
|
EmitSourceDepth(" uint2(0u, 16u)) & 65535u;\n");
|
|
EmitSourceDepth("xe_pv.xy = f16tof32(xe_vertex_element.xy);\n");
|
|
EmitSourceDepth("xe_pv.zw = float2(0.0, 1.0);\n");
|
|
break;
|
|
case VertexFormat::k_16_16_16_16_FLOAT:
|
|
EmitSourceDepth("xe_vertex_element = (xe_vertex_element.xxxx >>\n");
|
|
EmitSourceDepth(" uint4(0u, 16u, 0u, 16u)) & 65535u;\n");
|
|
EmitSourceDepth("xe_pv = f16tof32(xe_vertex_element);\n");
|
|
break;
|
|
case VertexFormat::k_32:
|
|
if (instr.attributes.is_signed) {
|
|
EmitSourceDepth("xe_pv.x = float(int(xe_vertex_element.x));\n");
|
|
} else {
|
|
EmitSourceDepth("xe_pv.x = float(xe_vertex_element.x);\n");
|
|
}
|
|
if (!instr.attributes.is_integer) {
|
|
EmitSourceDepth("xe_pv.x *= asfloat(0x%Xu);\n",
|
|
instr.attributes.is_signed ? 0x30000000 : 0x2F800000);
|
|
}
|
|
EmitSourceDepth("xe_pv.yzw = float3(0.0, 0.0, 1.0);\n");
|
|
break;
|
|
case VertexFormat::k_32_32:
|
|
if (instr.attributes.is_signed) {
|
|
EmitSourceDepth("xe_pv.xy = float2(int2(xe_vertex_element.xy));\n");
|
|
} else {
|
|
EmitSourceDepth("xe_pv.xy = float2(xe_vertex_element.xy);\n");
|
|
}
|
|
if (!instr.attributes.is_integer) {
|
|
EmitSourceDepth("xe_pv.xy *= asfloat(0x%Xu);\n",
|
|
instr.attributes.is_signed ? 0x30000000 : 0x2F800000);
|
|
}
|
|
EmitSourceDepth("xe_pv.zw = float2(0.0, 1.0);\n");
|
|
break;
|
|
case VertexFormat::k_32_32_32_32:
|
|
if (instr.attributes.is_signed) {
|
|
EmitSourceDepth("xe_pv = float4(int4(xe_vertex_element));\n");
|
|
} else {
|
|
EmitSourceDepth("xe_pv = float4(xe_vertex_element);\n");
|
|
}
|
|
if (!instr.attributes.is_integer) {
|
|
EmitSourceDepth("xe_pv *= asfloat(0x%Xu);\n",
|
|
instr.attributes.is_signed ? 0x30000000 : 0x2F800000);
|
|
}
|
|
break;
|
|
case VertexFormat::k_32_FLOAT:
|
|
EmitSourceDepth("xe_pv.x = asfloat(xe_vertex_element.x);\n");
|
|
EmitSourceDepth("xe_pv.yzw = float3(0.0, 0.0, 1.0);\n");
|
|
break;
|
|
case VertexFormat::k_32_32_FLOAT:
|
|
EmitSourceDepth("xe_pv.xy = asfloat(xe_vertex_element.xy);\n");
|
|
EmitSourceDepth("xe_pv.zw = float2(0.0, 1.0);\n");
|
|
break;
|
|
case VertexFormat::k_32_32_32_32_FLOAT:
|
|
EmitSourceDepth("xe_pv = asfloat(xe_vertex_element);\n");
|
|
break;
|
|
case VertexFormat::k_32_32_32_FLOAT:
|
|
EmitSourceDepth("xe_pv.xyz = asfloat(xe_vertex_element.xyz);\n");
|
|
EmitSourceDepth("xe_pv.w = 1.0;\n");
|
|
break;
|
|
}
|
|
|
|
EmitStoreResult(instr.result, false);
|
|
|
|
EndPredicatedInstruction(conditional_emitted);
|
|
}
|
|
|
|
uint32_t HlslShaderTranslator::AddSRVBinding(SRVType type,
|
|
uint32_t fetch_constant) {
|
|
for (uint32_t i = 0; i < srv_bindings_.size(); ++i) {
|
|
const SRVBinding& binding = srv_bindings_[i];
|
|
if (binding.type == type && binding.fetch_constant == fetch_constant) {
|
|
return i;
|
|
}
|
|
}
|
|
SRVBinding new_binding;
|
|
new_binding.type = type;
|
|
new_binding.fetch_constant = fetch_constant;
|
|
srv_bindings_.push_back(new_binding);
|
|
return uint32_t(srv_bindings_.size() - 1);
|
|
}
|
|
|
|
uint32_t HlslShaderTranslator::AddSampler(uint32_t fetch_constant) {
|
|
for (uint32_t i = 0; i < sampler_count_; ++i) {
|
|
if (sampler_fetch_constants_[i] == fetch_constant) {
|
|
return i;
|
|
}
|
|
}
|
|
sampler_fetch_constants_[sampler_count_] = fetch_constant;
|
|
return sampler_count_++;
|
|
}
|
|
|
|
void HlslShaderTranslator::ProcessTextureFetchInstruction(
|
|
const ParsedTextureFetchInstruction& instr) {
|
|
EmitSourceDepth("// ");
|
|
instr.Disassemble(&source_inner_);
|
|
|
|
bool conditional_emitted = BeginPredicatedInstruction(
|
|
instr.is_predicated, instr.predicate_condition);
|
|
|
|
// TODO(Triang3l): Texture fetch when textures are added.
|
|
EmitSourceDepth("xe_pv = (1.0).xxxx;\n");
|
|
|
|
EmitStoreResult(instr.result, false);
|
|
|
|
EndPredicatedInstruction(conditional_emitted);
|
|
}
|
|
|
|
void HlslShaderTranslator::ProcessVectorAluInstruction(
|
|
const ParsedAluInstruction& instr) {
|
|
bool conditional_emitted = BeginPredicatedInstruction(
|
|
instr.is_predicated, instr.predicate_condition);
|
|
|
|
for (size_t i = 0; i < instr.operand_count; ++i) {
|
|
EmitLoadOperand(i, instr.operands[i]);
|
|
}
|
|
|
|
switch (instr.vector_opcode) {
|
|
case AluVectorOpcode::kAdd:
|
|
EmitSourceDepth("xe_pv = xe_src0 + xe_src1;\n");
|
|
break;
|
|
case AluVectorOpcode::kMul:
|
|
EmitSourceDepth("xe_pv = xe_src0 * xe_src1;\n");
|
|
break;
|
|
case AluVectorOpcode::kMax:
|
|
EmitSourceDepth("xe_pv = max(xe_src0, xe_src1);\n");
|
|
break;
|
|
case AluVectorOpcode::kSeq:
|
|
EmitSourceDepth("xe_pv = float4(xe_src0 == xe_src1);\n");
|
|
break;
|
|
case AluVectorOpcode::kSgt:
|
|
EmitSourceDepth("xe_pv = float4(xe_src0 > xe_src1);\n");
|
|
break;
|
|
case AluVectorOpcode::kSge:
|
|
EmitSourceDepth("xe_pv = float4(xe_src0 >= xe_src1);\n");
|
|
break;
|
|
case AluVectorOpcode::kSne:
|
|
EmitSourceDepth("xe_pv = float4(xe_src0 != xe_src1);\n");
|
|
break;
|
|
case AluVectorOpcode::kFrc:
|
|
EmitSourceDepth("xe_pv = frac(xe_src0);\n");
|
|
break;
|
|
case AluVectorOpcode::kTrunc:
|
|
EmitSourceDepth("xe_pv = trunc(xe_src0);\n");
|
|
break;
|
|
case AluVectorOpcode::kFloor:
|
|
EmitSourceDepth("xe_pv = floor(xe_src0);\n");
|
|
break;
|
|
case AluVectorOpcode::kMad:
|
|
EmitSourceDepth("xe_pv = xe_src0 * xe_src1 + xe_src2;\n");
|
|
break;
|
|
case AluVectorOpcode::kCndEq:
|
|
EmitSourceDepth(
|
|
"xe_pv = lerp(xe_src2, xe_src1, float4(xe_src0 == (0.0).xxxx));\n");
|
|
break;
|
|
case AluVectorOpcode::kCndGe:
|
|
EmitSourceDepth(
|
|
"xe_pv = lerp(xe_src2, xe_src1, float4(xe_src0 >= (0.0).xxxx));\n");
|
|
break;
|
|
case AluVectorOpcode::kCndGt:
|
|
EmitSourceDepth(
|
|
"xe_pv = lerp(xe_src2, xe_src1, float4(xe_src0 > (0.0).xxxx));\n");
|
|
break;
|
|
case AluVectorOpcode::kDp4:
|
|
EmitSourceDepth("xe_pv = dot(xe_src0, xe_src1).xxxx;\n");
|
|
break;
|
|
case AluVectorOpcode::kDp3:
|
|
EmitSourceDepth("xe_pv = dot(xe_src0.xyz, xe_src1.xyz).xxxx;\n");
|
|
break;
|
|
case AluVectorOpcode::kDp2Add:
|
|
EmitSourceDepth(
|
|
"xe_pv = (dot(xe_src0.xy, xe_src1.xy) + xe_src2.x).xxxx;\n");
|
|
break;
|
|
case AluVectorOpcode::kCube:
|
|
EmitSourceDepth("xe_pv = XeCubeTo2D(xe_src0.xyz);\n");
|
|
cube_used_ = true;
|
|
break;
|
|
case AluVectorOpcode::kMax4:
|
|
EmitSourceDepth("xe_pv.xy = max(xe_src0.xy, xe_src0.zw);\n");
|
|
EmitSourceDepth("xe_pv.xxxx = max(xe_pv.x, xe_pv.y);\n");
|
|
break;
|
|
case AluVectorOpcode::kSetpEqPush:
|
|
cf_exec_pred_ = false;
|
|
EmitSourceDepth("xe_p0 = xe_src0.w == 0.0 && xe_src1.w == 0.0;\n");
|
|
EmitSourceDepth("xe_pv = (xe_src0.x == 0.0 && xe_src1.x == 0.0 ? "
|
|
"0.0 : xe_src0.x + 1.0).xxxx;\n");
|
|
break;
|
|
case AluVectorOpcode::kSetpNePush:
|
|
cf_exec_pred_ = false;
|
|
EmitSourceDepth("xe_p0 = xe_src0.w == 0.0 && xe_src1.w != 0.0;\n");
|
|
EmitSourceDepth("xe_pv = (xe_src0.x == 0.0 && xe_src1.x != 0.0 ? "
|
|
"0.0 : xe_src0.x + 1.0).xxxx;\n");
|
|
break;
|
|
case AluVectorOpcode::kSetpGtPush:
|
|
cf_exec_pred_ = false;
|
|
EmitSourceDepth("xe_p0 = xe_src0.w == 0.0 && xe_src1.w > 0.0;\n");
|
|
EmitSourceDepth("xe_pv = (xe_src0.x == 0.0 && xe_src1.x > 0.0 ? "
|
|
"0.0 : xe_src0.x + 1.0).xxxx;\n");
|
|
break;
|
|
case AluVectorOpcode::kSetpGePush:
|
|
cf_exec_pred_ = false;
|
|
EmitSourceDepth("xe_p0 = xe_src0.w == 0.0 && xe_src1.w >= 0.0;\n");
|
|
EmitSourceDepth("xe_pv = (xe_src0.x == 0.0 && xe_src1.x >= 0.0 ? "
|
|
"0.0 : xe_src0.x + 1.0).xxxx;\n");
|
|
break;
|
|
case AluVectorOpcode::kKillEq:
|
|
EmitSourceDepth("xe_pv.xxxx = float(any(xe_src0 == xe_src1));\n");
|
|
EmitSourceDepth("clip(-xe_pv.x);\n");
|
|
break;
|
|
case AluVectorOpcode::kKillGt:
|
|
EmitSourceDepth("xe_pv.xxxx = float(any(xe_src0 > xe_src1));\n");
|
|
EmitSourceDepth("clip(-xe_pv.x);\n");
|
|
break;
|
|
case AluVectorOpcode::kKillGe:
|
|
EmitSourceDepth("xe_pv.xxxx = float(any(xe_src0 >= xe_src1));\n");
|
|
EmitSourceDepth("clip(-xe_pv.x);\n");
|
|
break;
|
|
case AluVectorOpcode::kKillNe:
|
|
EmitSourceDepth("xe_pv.xxxx = float(any(xe_src0 != xe_src1));\n");
|
|
EmitSourceDepth("clip(-xe_pv.x);\n");
|
|
break;
|
|
case AluVectorOpcode::kDst:
|
|
EmitSourceDepth("xe_pv.x = 1.0;\n");
|
|
EmitSourceDepth("xe_pv.y = xe_src0.y * xe_src1.y;\n");
|
|
EmitSourceDepth("xe_pv.z = xe_src0.z;\n");
|
|
EmitSourceDepth("xe_pv.w = xe_src1.w;\n");
|
|
break;
|
|
case AluVectorOpcode::kMaxA:
|
|
EmitSourceDepth("xe_a0 = clamp(int(round(xe_src0.w)), -256, 255);\n");
|
|
EmitSourceDepth("xe_pv = max(xe_src0, xe_src1);\n");
|
|
break;
|
|
}
|
|
|
|
EmitStoreResult(instr.result, false);
|
|
|
|
EndPredicatedInstruction(conditional_emitted);
|
|
}
|
|
|
|
void HlslShaderTranslator::ProcessScalarAluInstruction(
|
|
const ParsedAluInstruction& instr) {
|
|
bool conditional_emitted = BeginPredicatedInstruction(
|
|
instr.is_predicated, instr.predicate_condition);
|
|
|
|
for (size_t i = 0; i < instr.operand_count; ++i) {
|
|
EmitLoadOperand(i, instr.operands[i]);
|
|
}
|
|
|
|
switch (instr.scalar_opcode) {
|
|
case AluScalarOpcode::kAdds:
|
|
EmitSourceDepth("xe_ps = xe_src0.x + xe_src0.y;\n");
|
|
break;
|
|
case AluScalarOpcode::kAddsPrev:
|
|
EmitSourceDepth("xe_ps += xe_src0.x;\n");
|
|
break;
|
|
case AluScalarOpcode::kMuls:
|
|
EmitSourceDepth("xe_ps = xe_src0.x * xe_src0.y;\n");
|
|
break;
|
|
case AluScalarOpcode::kMulsPrev:
|
|
EmitSourceDepth("xe_ps *= xe_src0.x;\n");
|
|
break;
|
|
case AluScalarOpcode::kMulsPrev2:
|
|
EmitSourceDepth(
|
|
"xe_ps = (xe_ps == -XE_FLT_MAX || (isinf(xe_ps) && xe_ps < 0.0)\n");
|
|
EmitSourceDepth(
|
|
" || isnan(xe_ps) || xe_src0.y <= 0.0 || isnan(xe_src0.y)) ?\n");
|
|
EmitSourceDepth(" -XE_FLT_MAX : xe_src0.x * xe_ps;\n");
|
|
break;
|
|
case AluScalarOpcode::kMaxs:
|
|
EmitSourceDepth("xe_ps = max(xe_src0.x, xe_src0.y);\n");
|
|
break;
|
|
case AluScalarOpcode::kMins:
|
|
EmitSourceDepth("xe_ps = max(xe_src0.x, xe_src0.y);\n");
|
|
break;
|
|
case AluScalarOpcode::kSeqs:
|
|
EmitSourceDepth("xe_ps = float(xe_src0.x == 0.0);\n");
|
|
break;
|
|
case AluScalarOpcode::kSgts:
|
|
EmitSourceDepth("xe_ps = float(xe_src0.x > 0.0);\n");
|
|
break;
|
|
case AluScalarOpcode::kSges:
|
|
EmitSourceDepth("xe_ps = float(xe_src0.x >= 0.0);\n");
|
|
break;
|
|
case AluScalarOpcode::kSnes:
|
|
EmitSourceDepth("xe_ps = float(xe_src0.x != 0.0);\n");
|
|
break;
|
|
case AluScalarOpcode::kFrcs:
|
|
EmitSourceDepth("xe_ps = frac(xe_src0.x);\n");
|
|
break;
|
|
case AluScalarOpcode::kTruncs:
|
|
EmitSourceDepth("xe_ps = trunc(xe_src0.x);\n");
|
|
break;
|
|
case AluScalarOpcode::kFloors:
|
|
EmitSourceDepth("xe_ps = floor(xe_src0.x);\n");
|
|
break;
|
|
case AluScalarOpcode::kExp:
|
|
EmitSourceDepth("xe_ps = exp2(xe_src0.x);\n");
|
|
break;
|
|
case AluScalarOpcode::kLogc:
|
|
EmitSourceDepth("xe_ps = log2(xe_src0.x);\n");
|
|
EmitSourceDepth(
|
|
"xe_ps = (isinf(xe_ps) && xe_ps < 0.0) ? -XE_FLT_MAX : ps;\n");
|
|
break;
|
|
case AluScalarOpcode::kLog:
|
|
EmitSourceDepth("xe_ps = log2(xe_src0.x);\n");
|
|
break;
|
|
case AluScalarOpcode::kRcpc:
|
|
EmitSourceDepth(
|
|
"xe_ps = clamp(rcp(xe_src0.x), -XE_FLT_MAX, XE_FLT_MAX);\n");
|
|
break;
|
|
case AluScalarOpcode::kRcpf:
|
|
EmitSourceDepth("xe_ps = rcp(xe_src0.x);\n");
|
|
EmitSourceDepth("xe_ps *= float(!isinf(xe_ps));\n");
|
|
break;
|
|
case AluScalarOpcode::kRcp:
|
|
EmitSourceDepth("xe_ps = rcp(xe_src0.x);\n");
|
|
break;
|
|
case AluScalarOpcode::kRsqc:
|
|
EmitSourceDepth(
|
|
"xe_ps = clamp(rsqrt(xe_src0.x), -XE_FLT_MAX, XE_FLT_MAX);\n");
|
|
break;
|
|
case AluScalarOpcode::kRsqf:
|
|
EmitSourceDepth("xe_ps = rsqrt(xe_src0.x);\n");
|
|
EmitSourceDepth("xe_ps *= float(!isinf(xe_ps));\n");
|
|
break;
|
|
case AluScalarOpcode::kRsq:
|
|
EmitSourceDepth("xe_ps = rsqrt(xe_src0.x);\n");
|
|
break;
|
|
case AluScalarOpcode::kMaxAs:
|
|
EmitSourceDepth("xe_a0 = clamp(int(round(xe_src0.x)), -256, 255);\n");
|
|
EmitSourceDepth("xe_ps = max(xe_src0.x, xe_src0.y);\n");
|
|
break;
|
|
case AluScalarOpcode::kMaxAsf:
|
|
EmitSourceDepth("xe_a0 = clamp(int(floor(xe_src0.x)), -256, 255);\n");
|
|
EmitSourceDepth("xe_ps = max(xe_src0.x, xe_src0.y);\n");
|
|
break;
|
|
case AluScalarOpcode::kSubs:
|
|
EmitSourceDepth("xe_ps = xe_src0.x - xe_src0.y;\n");
|
|
break;
|
|
case AluScalarOpcode::kSubsPrev:
|
|
EmitSourceDepth("xe_ps = xe_src0.x - xe_ps;\n");
|
|
break;
|
|
case AluScalarOpcode::kSetpEq:
|
|
cf_exec_pred_ = false;
|
|
EmitSourceDepth("xe_p0 = xe_src0.x == 0.0;\n");
|
|
EmitSourceDepth("xe_ps = float(!xe_p0);\n");
|
|
break;
|
|
case AluScalarOpcode::kSetpNe:
|
|
cf_exec_pred_ = false;
|
|
EmitSourceDepth("xe_p0 = xe_src0.x != 0.0;\n");
|
|
EmitSourceDepth("xe_ps = float(!xe_p0);\n");
|
|
break;
|
|
case AluScalarOpcode::kSetpGt:
|
|
cf_exec_pred_ = false;
|
|
EmitSourceDepth("xe_p0 = xe_src0.x > 0.0;\n");
|
|
EmitSourceDepth("xe_ps = float(!xe_p0);\n");
|
|
break;
|
|
case AluScalarOpcode::kSetpGe:
|
|
cf_exec_pred_ = false;
|
|
EmitSourceDepth("xe_p0 = xe_src0.x >= 0.0;\n");
|
|
EmitSourceDepth("xe_ps = float(!xe_p0);\n");
|
|
break;
|
|
case AluScalarOpcode::kSetpInv:
|
|
cf_exec_pred_ = false;
|
|
EmitSourceDepth("xe_p0 = xe_src0.x == 1.0;\n");
|
|
EmitSourceDepth(
|
|
"xe_ps = float(!xe_p0) * (xe_src0.x == 0.0 ? 1.0 : xe_src0.x);\n");
|
|
break;
|
|
case AluScalarOpcode::kSetpPop:
|
|
cf_exec_pred_ = false;
|
|
EmitSourceDepth("xe_ps = max(xe_src0.x - 1.0, 0.0);\n");
|
|
EmitSourceDepth("xe_p0 = xe_ps == 0.0;\n");
|
|
break;
|
|
case AluScalarOpcode::kSetpClr:
|
|
cf_exec_pred_ = false;
|
|
EmitSourceDepth("xe_ps = false;\n");
|
|
EmitSourceDepth("xe_p0 = XE_FLT_MAX;\n");
|
|
break;
|
|
case AluScalarOpcode::kSetpRstr:
|
|
cf_exec_pred_ = false;
|
|
EmitSourceDepth("xe_p0 = src0.x == 0.0;\n");
|
|
EmitSourceDepth("xe_ps = src0.x;\n");
|
|
break;
|
|
case AluScalarOpcode::kKillsEq:
|
|
EmitSourceDepth("xe_ps = float(xe_src0.x == 0.0);\n");
|
|
EmitSourceDepth("clip(-xe_ps);\n");
|
|
break;
|
|
case AluScalarOpcode::kKillsGt:
|
|
EmitSourceDepth("xe_ps = float(xe_src0.x > 0.0);\n");
|
|
EmitSourceDepth("clip(-xe_ps);\n");
|
|
break;
|
|
case AluScalarOpcode::kKillsGe:
|
|
EmitSourceDepth("xe_ps = float(xe_src0.x >= 0.0);\n");
|
|
EmitSourceDepth("clip(-xe_ps);\n");
|
|
break;
|
|
case AluScalarOpcode::kKillsNe:
|
|
EmitSourceDepth("xe_ps = float(xe_src0.x != 0.0);\n");
|
|
EmitSourceDepth("clip(-xe_ps);\n");
|
|
break;
|
|
case AluScalarOpcode::kKillsOne:
|
|
EmitSourceDepth("xe_ps = float(xe_src0.x == 1.0);\n");
|
|
EmitSourceDepth("clip(-xe_ps);\n");
|
|
break;
|
|
case AluScalarOpcode::kSqrt:
|
|
EmitSourceDepth("xe_ps = float(xe_src0.x);\n");
|
|
break;
|
|
case AluScalarOpcode::kMulsc0:
|
|
case AluScalarOpcode::kMulsc1:
|
|
EmitSourceDepth("xe_ps = xe_src0.x * xe_src1.x;\n");
|
|
break;
|
|
case AluScalarOpcode::kAddsc0:
|
|
case AluScalarOpcode::kAddsc1:
|
|
EmitSourceDepth("xe_ps = xe_src0.x + xe_src1.x;\n");
|
|
break;
|
|
case AluScalarOpcode::kSubsc0:
|
|
case AluScalarOpcode::kSubsc1:
|
|
EmitSourceDepth("xe_ps = xe_src0.x - xe_src1.x;\n");
|
|
break;
|
|
case AluScalarOpcode::kSin:
|
|
EmitSourceDepth("xe_ps = sin(xe_src0.x);\n");
|
|
break;
|
|
case AluScalarOpcode::kCos:
|
|
EmitSourceDepth("xe_ps = cos(xe_src0.x);\n");
|
|
break;
|
|
case AluScalarOpcode::kRetainPrev:
|
|
break;
|
|
}
|
|
|
|
EmitStoreResult(instr.result, true);
|
|
|
|
EndPredicatedInstruction(conditional_emitted);
|
|
}
|
|
|
|
void HlslShaderTranslator::ProcessAluInstruction(
|
|
const ParsedAluInstruction& instr) {
|
|
EmitSourceDepth("// ");
|
|
instr.Disassemble(&source_inner_);
|
|
|
|
switch (instr.type) {
|
|
case ParsedAluInstruction::Type::kNop:
|
|
break;
|
|
case ParsedAluInstruction::Type::kVector:
|
|
ProcessVectorAluInstruction(instr);
|
|
break;
|
|
case ParsedAluInstruction::Type::kScalar:
|
|
ProcessScalarAluInstruction(instr);
|
|
break;
|
|
}
|
|
}
|
|
|
|
} // namespace gpu
|
|
} // namespace xe
|