Mostly complete new GLSL translator (modulo flow control).

This commit is contained in:
Ben Vanik 2015-12-05 17:44:06 -08:00
parent 0058cae901
commit 2b3b423776
8 changed files with 1453 additions and 22 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,79 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2015 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_GPU_GLSL_SHADER_TRANSLATOR_H_
#define XENIA_GPU_GLSL_SHADER_TRANSLATOR_H_
#include <memory>
#include <string>
#include <vector>
#include "xenia/base/string_buffer.h"
#include "xenia/gpu/shader_translator.h"
namespace xe {
namespace gpu {
class GlslShaderTranslator : public ShaderTranslator {
public:
enum class Dialect {
kGL45,
};
GlslShaderTranslator(Dialect dialect);
~GlslShaderTranslator() override;
protected:
void EmitTranslationError(const char* message) override;
void EmitUnimplementedTranslationError() override;
void StartTranslation() override;
std::vector<uint8_t> CompleteTranslation() override;
void ProcessLabel(uint32_t cf_index) override;
void ProcessControlFlowNopInstruction() override;
void ProcessExecInstructionBegin(const ParsedExecInstruction& instr) override;
void ProcessExecInstructionEnd(const ParsedExecInstruction& instr) override;
void ProcessLoopStartInstruction(
const ParsedLoopStartInstruction& instr) override;
void ProcessLoopEndInstruction(
const ParsedLoopEndInstruction& instr) override;
void ProcessCallInstruction(const ParsedCallInstruction& instr) override;
void ProcessReturnInstruction(const ParsedReturnInstruction& instr) override;
void ProcessJumpInstruction(const ParsedJumpInstruction& instr) override;
void ProcessAllocInstruction(const ParsedAllocInstruction& instr) override;
void ProcessVertexFetchInstruction(
const ParsedVertexFetchInstruction& instr) override;
void ProcessTextureFetchInstruction(
const ParsedTextureFetchInstruction& instr) override;
void ProcessAluInstruction(const ParsedAluInstruction& instr) override;
private:
void Indent();
void Unindent();
void EmitLoadOperand(size_t i, const InstructionOperand& op);
void EmitStoreVectorResult(const InstructionResult& result);
void EmitStoreScalarResult(const InstructionResult& result);
void EmitStoreResult(const InstructionResult& result, const char* temp);
Dialect dialect_;
StringBuffer source_;
int depth_ = 0;
char depth_prefix_[16] = {0};
void ProcessVectorAluInstruction(const ParsedAluInstruction& instr);
void ProcessScalarAluInstruction(const ParsedAluInstruction& instr);
};
} // namespace gpu
} // namespace xe
#endif // XENIA_GPU_GLSL_SHADER_TRANSLATOR_H_

View File

@ -16,6 +16,7 @@
#include "xenia/base/logging.h"
#include "xenia/base/main.h"
#include "xenia/base/string.h"
#include "xenia/gpu/glsl_shader_translator.h"
#include "xenia/gpu/shader_translator.h"
#include "xenia/gpu/spirv_shader_translator.h"
#include "xenia/ui/spirv/spirv_disassembler.h"
@ -25,7 +26,7 @@ DEFINE_string(shader_input_type, "",
"'vs', 'ps', or unspecified to infer from the given filename.");
DEFINE_string(shader_output, "", "Output shader file path.");
DEFINE_string(shader_output_type, "ucode",
"Translator to use: [ucode, spirv, spirvtext].");
"Translator to use: [ucode, glsl45, spirv, spirvtext].");
namespace xe {
namespace gpu {
@ -82,6 +83,9 @@ int shader_compiler_main(const std::vector<std::wstring>& args) {
if (FLAGS_shader_output_type == "spirv" ||
FLAGS_shader_output_type == "spirvtext") {
translator = std::make_unique<SpirvShaderTranslator>();
} else if (FLAGS_shader_output_type == "glsl45") {
translator = std::make_unique<GlslShaderTranslator>(
GlslShaderTranslator::Dialect::kGL45);
} else {
translator = std::make_unique<UcodeShaderTranslator>();
}

View File

@ -537,10 +537,10 @@ class ShaderTranslator {
// Ucode disassembly buffer accumulated during translation.
StringBuffer& ucode_disasm_buffer() { return ucode_disasm_buffer_; }
// Emits a translation error that will be passed back in the result.
void EmitTranslationError(const char* message);
virtual void EmitTranslationError(const char* message);
// Emits a translation error indicating that the current translation is not
// implemented or supported.
void EmitUnimplementedTranslationError();
virtual void EmitUnimplementedTranslationError();
// Handles the start of translation.
// At this point the vertex and texture bindings have been gathered.

View File

@ -91,6 +91,9 @@ void DisassembleSourceOperand(const InstructionOperand& op, StringBuffer* out) {
out->Append('b');
break;
}
if (op.is_absolute_value) {
out->Append("_abs");
}
switch (op.storage_addressing_mode) {
case InstructionStorageAddressingMode::kStatic:
out->AppendFormat("%d", op.storage_index);
@ -102,9 +105,6 @@ void DisassembleSourceOperand(const InstructionOperand& op, StringBuffer* out) {
out->AppendFormat("[%d+aL]", op.storage_index);
break;
}
if (op.is_absolute_value) {
out->Append("_abs");
}
if (!op.is_standard_swizzle()) {
out->Append('.');
if (op.component_count == 1) {

View File

@ -933,7 +933,7 @@ enum class AluScalarOpcode {
// if (src0.a == 0.0) {
// dest.xyzw = 1.0;
// } else {
// dest.xyzw = src1.a;
// dest.xyzw = src0.a;
// }
// p0 = 0;
// }
@ -1186,7 +1186,7 @@ enum class AluVectorOpcode {
// Two-Element Dot Product and Add
// dp2add dest, src0, src1, src2
// dest.xyzw = src0.x * src1.x + src0.y * src1.y + src3.x;
// dest.xyzw = src0.x * src1.x + src0.y * src1.y + src2.x;
// Note: only pv.x contains the value.
kDp2Add = 17,

View File

@ -162,8 +162,8 @@
| System.Windows.Forms.AnchorStyles.Right)));
this.translationComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.translationComboBox.FormattingEnabled = true;
this.translationComboBox.Items.AddRange(new object[] {
"SPIRV"});
this.translationComboBox.Items.AddRange(
new object[]{"GLSL for GL4.5", "SPIRV"});
this.translationComboBox.Location = new System.Drawing.Point(1224, 0);
this.translationComboBox.Margin = new System.Windows.Forms.Padding(3, 0, 3, 0);
this.translationComboBox.Name = "translationComboBox";

View File

@ -5,6 +5,7 @@ using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
@ -18,6 +19,13 @@ namespace shader_playground {
public Editor() {
InitializeComponent();
var scrollUpdateTimer = new Timer();
scrollUpdateTimer.Interval = 200;
scrollUpdateTimer.Tick += (object sender, EventArgs e) => {
UpdateScrollStates();
};
scrollUpdateTimer.Start();
var compilerBinPath = Path.Combine(Directory.GetCurrentDirectory(),
Path.GetDirectoryName(compilerPath_));
compilerWatcher_ = new FileSystemWatcher(compilerBinPath, "*.exe");
@ -136,9 +144,9 @@ namespace shader_playground {
var disassembledSourceCode = compiledShader.ErrorsAndWarnings;
disassembledSourceCode = disassembledSourceCode.Replace("\n", Environment.NewLine);
if (disassembledSourceCode.IndexOf("// PDB hint 00000000-00000000-00000000") == -1) {
outputTextBox.Text = disassembledSourceCode;
compilerUcodeTextBox.Text = "";
wordsTextBox.Text = "";
UpdateTextBox(outputTextBox, disassembledSourceCode, false);
UpdateTextBox(compilerUcodeTextBox, "", false);
UpdateTextBox(wordsTextBox, "", false);
return;
}
var prefix = disassembledSourceCode.Substring(
@ -155,7 +163,7 @@ namespace shader_playground {
disassembledSourceCode =
warnings + disassembledSourceCode.Substring(firstLine + 3);
disassembledSourceCode = disassembledSourceCode.Trim();
outputTextBox.Text = disassembledSourceCode;
UpdateTextBox(outputTextBox, disassembledSourceCode, true);
string shaderType =
shaderSourceCode.IndexOf("xvs_") == -1 ? "ps" : "vs";
@ -163,7 +171,7 @@ namespace shader_playground {
if (ucodeWords != null) {
TryCompiler(shaderType, ucodeWords);
} else {
compilerUcodeTextBox.Text = "";
UpdateTextBox(compilerUcodeTextBox, "", false);
}
if (compilerUcodeTextBox.Text.Length > 0) {
@ -191,7 +199,7 @@ namespace shader_playground {
File.WriteAllBytes(ucodePath, ucodeBytes);
if (!File.Exists(compilerPath_)) {
compilerUcodeTextBox.Text = "Compiler not found: " + compilerPath_;
UpdateTextBox(compilerUcodeTextBox, "Compiler not found: " + compilerPath_, false);
return;
}
@ -209,15 +217,18 @@ namespace shader_playground {
process.WaitForExit();
}
string disasmText = File.ReadAllText(ucodeDisasmPath);
compilerUcodeTextBox.Text = disasmText.Replace("\n", Environment.NewLine);
UpdateTextBox(compilerUcodeTextBox, disasmText.Replace("\n", Environment.NewLine), true);
} catch {
compilerUcodeTextBox.Text = "COMPILER FAILURE";
UpdateTextBox(compilerUcodeTextBox, "COMPILER FAILURE", false);
}
string outputType;
switch (translationComboBox.SelectedIndex) {
default:
case 0:
outputType = "glsl45";
break;
case 1:
outputType = "spirvtext";
break;
}
@ -236,9 +247,9 @@ namespace shader_playground {
process.WaitForExit();
}
string disasmText = File.ReadAllText(translatedDisasmPath);
compilerTranslatedTextBox.Text = disasmText.Replace("\n", Environment.NewLine);
UpdateTextBox(compilerTranslatedTextBox, disasmText.Replace("\n", Environment.NewLine), true);
} catch {
compilerTranslatedTextBox.Text = "COMPILER FAILURE";
UpdateTextBox(compilerTranslatedTextBox, "COMPILER FAILURE", false);
}
}
@ -262,6 +273,66 @@ namespace shader_playground {
}
}
void UpdateScrollStates() {
foreach (var handle in scrollPreserve_.Keys) {
if (scrollPreserve_[handle]) {
var scrollInfo = new ScrollInfo();
scrollInfo.cbSize = Marshal.SizeOf(scrollInfo);
scrollInfo.fMask = (uint)ScrollInfoMask.SIF_TRACKPOS;
bool hasScrollInfo = GetScrollInfo(handle, SB_VERT, ref scrollInfo);
scrollPositions_[handle] = scrollInfo.nTrackPos;
}
}
}
Dictionary<IntPtr, bool> scrollPreserve_ = new Dictionary<IntPtr, bool>();
Dictionary<IntPtr, int> scrollPositions_ = new Dictionary<IntPtr, int>();
void UpdateTextBox(TextBox textBox, string value, bool preserveScroll) {
scrollPreserve_[textBox.Handle] = preserveScroll;
textBox.Text = value;
int previousScroll;
if (!scrollPositions_.TryGetValue(textBox.Handle, out previousScroll)) {
previousScroll = 0;
}
var scrollInfo = new ScrollInfo();
scrollInfo.cbSize = Marshal.SizeOf(scrollInfo);
scrollInfo.fMask = (uint)ScrollInfoMask.SIF_TRACKPOS;
scrollInfo.nTrackPos = previousScroll;
SetScrollInfo(textBox.Handle, SB_VERT, ref scrollInfo, 1);
var ptrWparam = new IntPtr(SB_THUMBPOSITION | previousScroll << 16);
SendMessage(textBox.Handle, WM_VSCROLL, ptrWparam, IntPtr.Zero);
}
private const int SB_VERT = 1;
private const uint SB_THUMBPOSITION = 4;
private const uint WM_VSCROLL = 0x115;
public enum ScrollInfoMask : uint {
SIF_RANGE = 0x1,
SIF_PAGE = 0x2,
SIF_POS = 0x4,
SIF_DISABLENOSCROLL = 0x8,
SIF_TRACKPOS = 0x10,
SIF_ALL = (SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS),
}
private struct ScrollInfo {
public int cbSize;
public uint fMask;
public int nMin;
public int nMax;
public int nPage;
public int nPos;
public int nTrackPos;
}
[DllImport("user32.dll", SetLastError = true)]
private static extern bool GetScrollInfo(IntPtr hwnd, int bar, ref ScrollInfo scrollInfo);
[DllImport("user32.dll", SetLastError = true)]
private static extern bool SetScrollInfo(IntPtr hwnd, int bar, ref ScrollInfo scrollInfo, int redraw);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
bool MemCmp(byte[] a1, byte[] b1) {
if (a1 == null || b1 == null) {
return false;
@ -281,7 +352,7 @@ namespace shader_playground {
uint[] ExtractAndDumpWords(string shaderType, byte[] shaderCode) {
if (shaderCode == null || shaderCode.Length == 0) {
wordsTextBox.Text = "";
UpdateTextBox(wordsTextBox, "", false);
return null;
}
@ -302,7 +373,7 @@ namespace shader_playground {
}
sb.Append("};" + Environment.NewLine);
sb.Append("shader_type = ShaderType::" + (shaderType == "vs" ? "kVertex" : "kPixel") + ";" + Environment.NewLine);
wordsTextBox.Text = sb.ToString();
UpdateTextBox(wordsTextBox, sb.ToString(), true);
wordsTextBox.SelectAll();
return swappedCode;