Merge branch 'vulkan'

This commit is contained in:
Dr. Chat
2016-06-11 19:23:23 -05:00
164 changed files with 51895 additions and 4707 deletions

View File

@@ -1019,9 +1019,8 @@ bool CommandProcessor::ExecutePacketType3_EVENT_WRITE_EXT(RingBuffer* reader,
1, // max z
};
assert_true(endianness == Endian::k8in16);
xe::copy_and_swap_16_aligned(
reinterpret_cast<uint16_t*>(memory_->TranslatePhysical(address)), extents,
xe::countof(extents));
xe::copy_and_swap_16_aligned(memory_->TranslatePhysical(address), extents,
xe::countof(extents));
trace_writer_.WriteMemoryWrite(CpuToGpu(address), sizeof(extents));
return true;
}

View File

@@ -84,9 +84,9 @@ class CommandProcessor {
swap_request_handler_ = fn;
}
void RequestFrameTrace(const std::wstring& root_path);
void BeginTracing(const std::wstring& root_path);
void EndTracing();
virtual void RequestFrameTrace(const std::wstring& root_path);
virtual void BeginTracing(const std::wstring& root_path);
virtual void EndTracing();
void InitializeRingBuffer(uint32_t ptr, uint32_t page_count);
void EnableReadPointerWriteBack(uint32_t ptr, uint32_t block_size);

View File

@@ -1410,7 +1410,7 @@ GL4CommandProcessor::UpdateStatus GL4CommandProcessor::PopulateVertexBuffers() {
// as we copy and only if it differs from the previous value committing
// it (and if it matches just discard and reuse).
xe::copy_and_swap_32_aligned(
reinterpret_cast<uint32_t*>(allocation.host_ptr),
allocation.host_ptr,
memory_->TranslatePhysical<const uint32_t*>(fetch->address << 2),
valid_range / 4);

View File

@@ -7,8 +7,8 @@
******************************************************************************
*/
#ifndef XENIA_GPU_GL4_COMMAND_PROCESSOR_H_
#define XENIA_GPU_GL4_COMMAND_PROCESSOR_H_
#ifndef XENIA_GPU_GL4_GL4_COMMAND_PROCESSOR_H_
#define XENIA_GPU_GL4_GL4_COMMAND_PROCESSOR_H_
#include <atomic>
#include <cstring>
@@ -234,4 +234,4 @@ class GL4CommandProcessor : public CommandProcessor {
} // namespace gpu
} // namespace xe
#endif // XENIA_GPU_GL4_COMMAND_PROCESSOR_H_
#endif // XENIA_GPU_GL4_GL4_COMMAND_PROCESSOR_H_

View File

@@ -427,7 +427,7 @@ TextureCache::TextureEntry* TextureCache::LookupOrInsertTexture(
// Not found, create.
auto entry = std::make_unique<TextureEntry>();
entry->texture_info = texture_info;
entry->write_watch_handle = 0;
entry->access_watch_handle = 0;
entry->pending_invalidation = false;
entry->handle = 0;
@@ -442,6 +442,7 @@ TextureCache::TextureEntry* TextureCache::LookupOrInsertTexture(
// Found! Acquire the handle and remove the readbuffer entry.
read_buffer_textures_.erase(it);
entry->handle = read_buffer_entry->handle;
entry->access_watch_handle = read_buffer_entry->access_watch_handle;
delete read_buffer_entry;
// TODO(benvanik): set more texture properties? swizzle/etc?
auto entry_ptr = entry.get();
@@ -495,14 +496,15 @@ TextureCache::TextureEntry* TextureCache::LookupOrInsertTexture(
// Add a write watch. If any data in the given range is touched we'll get a
// callback and evict the texture. We could reuse the storage, though the
// driver is likely in a better position to pool that kind of stuff.
entry->write_watch_handle = memory_->AddPhysicalWriteWatch(
entry->access_watch_handle = memory_->AddPhysicalAccessWatch(
texture_info.guest_address, texture_info.input_length,
cpu::MMIOHandler::kWatchWrite,
[](void* context_ptr, void* data_ptr, uint32_t address) {
auto self = reinterpret_cast<TextureCache*>(context_ptr);
auto touched_entry = reinterpret_cast<TextureEntry*>(data_ptr);
// Clear watch handle first so we don't redundantly
// remove.
touched_entry->write_watch_handle = 0;
touched_entry->access_watch_handle = 0;
touched_entry->pending_invalidation = true;
// Add to pending list so Scavenge will clean it up.
self->invalidated_textures_mutex_.lock();
@@ -574,14 +576,27 @@ GLuint TextureCache::ConvertTexture(Blitter* blitter, uint32_t guest_address,
dest_rect, GL_LINEAR, swap_channels);
}
// HACK: remove texture from write watch list so readback won't kill us.
// Not needed now, as readback is disabled.
/*
if (texture_entry->write_watch_handle) {
memory_->CancelWriteWatch(texture_entry->write_watch_handle);
texture_entry->write_watch_handle = 0;
// Setup a read/write access watch. If the game tries to touch the memory
// we were supposed to populate with this texture, then we'll actually
// populate it.
if (texture_entry->access_watch_handle) {
memory_->CancelAccessWatch(texture_entry->access_watch_handle);
texture_entry->access_watch_handle = 0;
}
//*/
texture_entry->access_watch_handle = memory_->AddPhysicalAccessWatch(
guest_address, texture_entry->texture_info.input_length,
cpu::MMIOHandler::kWatchReadWrite,
[](void* context, void* data, uint32_t address) {
auto touched_entry = reinterpret_cast<TextureEntry*>(data);
touched_entry->access_watch_handle = 0;
// This happens. RDR resolves to a texture then upsizes it, BF1943
// writes to a resolved texture.
// TODO (for Vulkan): Copy this texture back into system memory.
// assert_always();
},
nullptr, texture_entry);
return texture_entry->handle;
}
@@ -618,6 +633,20 @@ GLuint TextureCache::ConvertTexture(Blitter* blitter, uint32_t guest_address,
entry->block_height = block_height;
entry->format = format;
entry->access_watch_handle = memory_->AddPhysicalAccessWatch(
guest_address, block_height * block_width * 4,
cpu::MMIOHandler::kWatchReadWrite,
[](void* context, void* data, uint32_t address) {
auto entry = reinterpret_cast<ReadBufferTexture*>(data);
entry->access_watch_handle = 0;
// This happens. RDR resolves to a texture then upsizes it, BF1943
// writes to a resolved texture.
// TODO (for Vulkan): Copy this texture back into system memory.
// assert_always();
},
nullptr, entry.get());
glCreateTextures(GL_TEXTURE_2D, 1, &entry->handle);
glTextureParameteri(entry->handle, GL_TEXTURE_BASE_LEVEL, 0);
glTextureParameteri(entry->handle, GL_TEXTURE_MAX_LEVEL, 1);
@@ -636,9 +665,9 @@ GLuint TextureCache::ConvertTexture(Blitter* blitter, uint32_t guest_address,
}
void TextureCache::EvictTexture(TextureEntry* entry) {
if (entry->write_watch_handle) {
memory_->CancelWriteWatch(entry->write_watch_handle);
entry->write_watch_handle = 0;
if (entry->access_watch_handle) {
memory_->CancelAccessWatch(entry->access_watch_handle);
entry->access_watch_handle = 0;
}
for (auto& view : entry->views) {
@@ -662,19 +691,13 @@ void TextureSwap(Endian endianness, void* dest, const void* src,
size_t length) {
switch (endianness) {
case Endian::k8in16:
xe::copy_and_swap_16_aligned(reinterpret_cast<uint16_t*>(dest),
reinterpret_cast<const uint16_t*>(src),
length / 2);
xe::copy_and_swap_16_aligned(dest, src, length / 2);
break;
case Endian::k8in32:
xe::copy_and_swap_32_aligned(reinterpret_cast<uint32_t*>(dest),
reinterpret_cast<const uint32_t*>(src),
length / 4);
xe::copy_and_swap_32_aligned(dest, src, length / 4);
break;
case Endian::k16in32: // Swap high and low 16 bits within a 32 bit word
xe::copy_and_swap_16_in_32_aligned(reinterpret_cast<uint32_t*>(dest),
reinterpret_cast<const uint32_t*>(src),
length);
xe::copy_and_swap_16_in_32_aligned(dest, src, length);
break;
default:
case Endian::kUnspecified:

View File

@@ -44,7 +44,7 @@ class TextureCache {
};
struct TextureEntry {
TextureInfo texture_info;
uintptr_t write_watch_handle;
uintptr_t access_watch_handle;
GLuint handle;
bool pending_invalidation;
std::vector<std::unique_ptr<TextureEntryView>> views;
@@ -74,8 +74,12 @@ class TextureCache {
TextureFormat format, bool swap_channels,
GLuint src_texture, Rect2D src_rect, Rect2D dest_rect);
TextureEntry* LookupAddress(uint32_t guest_address, uint32_t width,
uint32_t height, TextureFormat format);
private:
struct ReadBufferTexture {
uintptr_t access_watch_handle;
uint32_t guest_address;
uint32_t logical_width;
uint32_t logical_height;
@@ -90,8 +94,6 @@ class TextureCache {
void EvictSampler(SamplerEntry* entry);
TextureEntry* LookupOrInsertTexture(const TextureInfo& texture_info,
uint64_t opt_hash = 0);
TextureEntry* LookupAddress(uint32_t guest_address, uint32_t width,
uint32_t height, TextureFormat format);
void EvictTexture(TextureEntry* entry);
bool UploadTexture2D(GLuint texture, const TextureInfo& texture_info);

View File

@@ -7,6 +7,7 @@ project("xenia-gpu")
kind("StaticLib")
language("C++")
links({
"glslang-spirv",
"snappy",
"spirv-tools",
"xenia-base",
@@ -21,6 +22,8 @@ project("xenia-gpu")
project_root.."/third_party/gflags/src",
})
local_platform_files()
local_platform_files("spirv")
local_platform_files("spirv/passes")
group("src")
project("xenia-gpu-shader-compiler")
@@ -29,6 +32,7 @@ project("xenia-gpu-shader-compiler")
language("C++")
links({
"gflags",
"glslang-spirv",
"spirv-tools",
"xenia-base",
"xenia-gpu",

View File

@@ -99,6 +99,17 @@ struct InstructionResult {
bool has_all_writes() const {
return write_mask[0] && write_mask[1] && write_mask[2] && write_mask[3];
}
// Returns number of components written
uint32_t num_writes() const {
uint32_t total = 0;
for (int i = 0; i < 4; i++) {
if (write_mask[i]) {
total++;
}
}
return total;
}
// Returns true if any non-constant components are written.
bool stores_non_constants() const {
for (int i = 0; i < 4; ++i) {
@@ -493,6 +504,24 @@ class Shader {
ParsedTextureFetchInstruction fetch_instr;
};
struct ConstantRegisterMap {
// Bitmap of all kConstantFloat registers read by the shader.
// Any shader can only read up to 256 of the 512, and the base is dependent
// on the shader type. Each bit corresponds to a storage index from the type
// base, so bit 0 in a vertex shader is register 0, and bit 0 in a fragment
// shader is register 256.
uint64_t float_bitmap[256 / 64];
// Bitmap of all kConstantInt registers read by the shader.
// Each bit corresponds to a storage index [0-31].
uint32_t int_bitmap;
// Bitmap of all kConstantBool registers read by the shader.
// Each bit corresponds to a storage index [0-255].
uint32_t bool_bitmap[256 / 32];
// Computed byte count of all registers required when packed.
uint32_t packed_byte_length;
};
Shader(ShaderType shader_type, uint64_t ucode_data_hash,
const uint32_t* ucode_dwords, size_t ucode_dword_count);
virtual ~Shader();
@@ -518,12 +547,20 @@ class Shader {
return texture_bindings_;
}
// Bitmaps of all constant registers accessed by the shader.
const ConstantRegisterMap& constant_register_map() const {
return constant_register_map_;
}
// Returns true if the given color target index [0-3].
bool writes_color_target(int i) const { return writes_color_targets_[i]; }
// True if the shader was translated and prepared without error.
bool is_valid() const { return is_valid_; }
// True if the shader has already been translated.
bool is_translated() const { return is_translated_; }
// Errors that occurred during translation.
const std::vector<Error>& errors() const { return errors_; }
@@ -564,9 +601,11 @@ class Shader {
std::vector<VertexBinding> vertex_bindings_;
std::vector<TextureBinding> texture_bindings_;
ConstantRegisterMap constant_register_map_ = {0};
bool writes_color_targets_[4] = {false, false, false, false};
bool is_valid_ = false;
bool is_translated_ = false;
std::vector<Error> errors_;
std::string ucode_disassembly_;

View File

@@ -14,6 +14,7 @@
#include <set>
#include <string>
#include "xenia/base/logging.h"
#include "xenia/base/math.h"
namespace xe {
@@ -50,16 +51,18 @@ void ShaderTranslator::Reset() {
ucode_disasm_buffer_.Reset();
ucode_disasm_line_number_ = 0;
previous_ucode_disasm_scan_offset_ = 0;
register_count_ = 64;
total_attrib_count_ = 0;
vertex_bindings_.clear();
texture_bindings_.clear();
std::memset(&constant_register_map_, 0, sizeof(constant_register_map_));
for (size_t i = 0; i < xe::countof(writes_color_targets_); ++i) {
writes_color_targets_[i] = false;
}
}
bool ShaderTranslator::GatherAllBindingInformation(Shader* shader) {
// FIXME: This is kind of silly.
// DEPRECATED: remove this codepath when GL4 goes away.
Reset();
shader_type_ = shader->type();
@@ -93,9 +96,21 @@ bool ShaderTranslator::GatherAllBindingInformation(Shader* shader) {
return true;
}
bool ShaderTranslator::Translate(Shader* shader,
xenos::xe_gpu_program_cntl_t cntl) {
Reset();
register_count_ = shader->type() == ShaderType::kVertex ? cntl.vs_regs + 1
: cntl.ps_regs + 1;
return TranslateInternal(shader);
}
bool ShaderTranslator::Translate(Shader* shader) {
Reset();
return TranslateInternal(shader);
}
bool ShaderTranslator::TranslateInternal(Shader* shader) {
shader_type_ = shader->type();
ucode_dwords_ = shader->ucode_dwords();
ucode_dword_count_ = shader->ucode_dword_count();
@@ -124,16 +139,36 @@ bool ShaderTranslator::Translate(Shader* shader) {
TranslateBlocks();
// Compute total bytes used by the register map.
// This saves us work later when we need to pack them.
constant_register_map_.packed_byte_length = 0;
for (int i = 0; i < 4; ++i) {
// Each bit indicates a vec4 (4 floats).
constant_register_map_.packed_byte_length +=
4 * 4 * xe::bit_count(constant_register_map_.float_bitmap[i]);
}
// Each bit indicates a single word.
constant_register_map_.packed_byte_length +=
4 * xe::bit_count(constant_register_map_.int_bitmap);
// Direct map between words and words we upload.
for (int i = 0; i < 8; ++i) {
if (constant_register_map_.bool_bitmap[i]) {
constant_register_map_.packed_byte_length += 4;
}
}
shader->errors_ = std::move(errors_);
shader->translated_binary_ = CompleteTranslation();
shader->ucode_disassembly_ = ucode_disasm_buffer_.to_string();
shader->vertex_bindings_ = std::move(vertex_bindings_);
shader->texture_bindings_ = std::move(texture_bindings_);
shader->constant_register_map_ = std::move(constant_register_map_);
for (size_t i = 0; i < xe::countof(writes_color_targets_); ++i) {
shader->writes_color_targets_[i] = writes_color_targets_[i];
}
shader->is_valid_ = true;
shader->is_translated_ = true;
for (const auto& error : shader->errors_) {
if (error.is_fatal) {
shader->is_valid_ = false;
@@ -141,6 +176,8 @@ bool ShaderTranslator::Translate(Shader* shader) {
}
}
PostTranslation(shader);
return shader->is_valid_;
}
@@ -331,7 +368,7 @@ bool ShaderTranslator::TranslateBlocks() {
// This is what freedreno does.
uint32_t max_cf_dword_index = static_cast<uint32_t>(ucode_dword_count_);
std::set<uint32_t> label_addresses;
for (uint32_t i = 0; i < max_cf_dword_index; i += 3) {
for (uint32_t i = 0, cf_index = 0; i < max_cf_dword_index; i += 3) {
ControlFlowInstruction cf_a;
ControlFlowInstruction cf_b;
UnpackControlFlowInstructions(ucode_dwords_ + i, &cf_a, &cf_b);
@@ -345,6 +382,11 @@ bool ShaderTranslator::TranslateBlocks() {
}
AddControlFlowTargetLabel(cf_a, &label_addresses);
AddControlFlowTargetLabel(cf_b, &label_addresses);
PreProcessControlFlowInstruction(cf_index, cf_a);
++cf_index;
PreProcessControlFlowInstruction(cf_index, cf_b);
++cf_index;
}
// Translate all instructions.
@@ -488,6 +530,8 @@ void ShaderTranslator::TranslateControlFlowCondExec(
i.instruction_count = cf.count();
i.type = ParsedExecInstruction::Type::kConditional;
i.bool_constant_index = cf.bool_address();
constant_register_map_.bool_bitmap[i.bool_constant_index / 32] |=
1 << (i.bool_constant_index % 32);
i.condition = cf.condition();
switch (cf.opcode()) {
case ControlFlowOpcode::kCondExec:
@@ -527,6 +571,7 @@ void ShaderTranslator::TranslateControlFlowLoopStart(
ParsedLoopStartInstruction i;
i.dword_index = cf_index_;
i.loop_constant_index = cf.loop_id();
constant_register_map_.int_bitmap |= 1 << i.loop_constant_index;
i.is_repeat = cf.is_repeat();
i.loop_skip_address = cf.address();
@@ -542,6 +587,7 @@ void ShaderTranslator::TranslateControlFlowLoopEnd(
i.is_predicated_break = cf.is_predicated_break();
i.predicate_condition = cf.condition();
i.loop_constant_index = cf.loop_id();
constant_register_map_.int_bitmap |= 1 << i.loop_constant_index;
i.loop_body_address = cf.address();
i.Disassemble(&ucode_disasm_buffer_);
@@ -562,6 +608,8 @@ void ShaderTranslator::TranslateControlFlowCondCall(
} else {
i.type = ParsedCallInstruction::Type::kConditional;
i.bool_constant_index = cf.bool_address();
constant_register_map_.bool_bitmap[i.bool_constant_index / 32] |=
1 << (i.bool_constant_index % 32);
i.condition = cf.condition();
}
@@ -593,6 +641,8 @@ void ShaderTranslator::TranslateControlFlowCondJmp(
} else {
i.type = ParsedJumpInstruction::Type::kConditional;
i.bool_constant_index = cf.bool_address();
constant_register_map_.bool_bitmap[i.bool_constant_index / 32] |=
1 << (i.bool_constant_index % 32);
i.condition = cf.condition();
}
@@ -950,16 +1000,19 @@ void ShaderTranslator::TranslateAluInstruction(const AluInstruction& op) {
return;
}
ParsedAluInstruction instr;
if (op.has_vector_op()) {
const auto& opcode_info =
alu_vector_opcode_infos_[static_cast<int>(op.vector_opcode())];
ParseAluVectorInstruction(op, opcode_info);
ParseAluVectorInstruction(op, opcode_info, instr);
ProcessAluInstruction(instr);
}
if (op.has_scalar_op()) {
const auto& opcode_info =
alu_scalar_opcode_infos_[static_cast<int>(op.scalar_opcode())];
ParseAluScalarInstruction(op, opcode_info);
ParseAluScalarInstruction(op, opcode_info, instr);
ProcessAluInstruction(instr);
}
}
@@ -1008,9 +1061,8 @@ void ParseAluInstructionOperand(const AluInstruction& op, int i,
uint32_t a = swizzle & 0x3;
out_op->components[0] = GetSwizzleFromComponentIndex(a);
} else if (swizzle_component_count == 2) {
swizzle >>= 4;
uint32_t a = ((swizzle >> 2) + 3) & 0x3;
uint32_t b = (swizzle + 2) & 0x3;
uint32_t a = ((swizzle >> 6) + 3) & 0x3;
uint32_t b = ((swizzle >> 0) + 0) & 0x3;
out_op->components[0] = GetSwizzleFromComponentIndex(a);
out_op->components[1] = GetSwizzleFromComponentIndex(b);
} else {
@@ -1052,8 +1104,8 @@ void ParseAluInstructionOperandSpecial(const AluInstruction& op,
}
void ShaderTranslator::ParseAluVectorInstruction(
const AluInstruction& op, const AluOpcodeInfo& opcode_info) {
ParsedAluInstruction i;
const AluInstruction& op, const AluOpcodeInfo& opcode_info,
ParsedAluInstruction& i) {
i.dword_index = 0;
i.type = ParsedAluInstruction::Type::kVector;
i.vector_opcode = op.vector_opcode();
@@ -1084,9 +1136,19 @@ void ShaderTranslator::ParseAluVectorInstruction(
i.result.storage_target = InstructionStorageTarget::kPointSize;
break;
default:
assert_true(dest_num < 16);
i.result.storage_target = InstructionStorageTarget::kInterpolant;
i.result.storage_index = dest_num;
if (dest_num < 16) {
i.result.storage_target = InstructionStorageTarget::kInterpolant;
i.result.storage_index = dest_num;
} else {
// Unimplemented.
// assert_always();
XELOGE(
"ShaderTranslator::ParseAluVectorInstruction: Unsupported write "
"to export %d",
dest_num);
i.result.storage_target = InstructionStorageTarget::kNone;
i.result.storage_index = 0;
}
break;
}
} else if (is_pixel_shader()) {
@@ -1150,16 +1212,22 @@ void ShaderTranslator::ParseAluVectorInstruction(
for (int j = 0; j < i.operand_count; ++j) {
ParseAluInstructionOperand(
op, j + 1, opcode_info.src_swizzle_component_count, &i.operands[j]);
// Track constant float register loads.
if (i.operands[j].storage_source ==
InstructionStorageSource::kConstantFloat) {
auto register_index = i.operands[j].storage_index;
constant_register_map_.float_bitmap[register_index / 64] |=
1ull << (register_index % 64);
}
}
i.Disassemble(&ucode_disasm_buffer_);
ProcessAluInstruction(i);
}
void ShaderTranslator::ParseAluScalarInstruction(
const AluInstruction& op, const AluOpcodeInfo& opcode_info) {
ParsedAluInstruction i;
const AluInstruction& op, const AluOpcodeInfo& opcode_info,
ParsedAluInstruction& i) {
i.dword_index = 0;
i.type = ParsedAluInstruction::Type::kScalar;
i.scalar_opcode = op.scalar_opcode();
@@ -1198,9 +1266,19 @@ void ShaderTranslator::ParseAluScalarInstruction(
i.result.storage_target = InstructionStorageTarget::kPointSize;
break;
default:
assert_true(dest_num < 16);
i.result.storage_target = InstructionStorageTarget::kInterpolant;
i.result.storage_index = dest_num;
if (dest_num < 16) {
i.result.storage_target = InstructionStorageTarget::kInterpolant;
i.result.storage_index = dest_num;
} else {
// Unimplemented.
// assert_always();
XELOGE(
"ShaderTranslator::ParseAluScalarInstruction: Unsupported write "
"to export %d",
dest_num);
i.result.storage_target = InstructionStorageTarget::kNone;
i.result.storage_index = 0;
}
break;
}
} else if (is_pixel_shader()) {
@@ -1243,17 +1321,22 @@ void ShaderTranslator::ParseAluScalarInstruction(
uint32_t reg2 = (static_cast<int>(op.scalar_opcode()) & 1) |
(src3_swizzle & 0x3C) | (op.src_is_temp(3) << 1);
int const_slot = (op.src_is_temp(1) || op.src_is_temp(2)) ? 1 : 0;
ParseAluInstructionOperandSpecial(
op, InstructionStorageSource::kConstantFloat, op.src_reg(3),
op.src_negate(3), 0, swiz_a, &i.operands[0]);
// Track constant float register loads.
auto register_index = i.operands[0].storage_index;
constant_register_map_.float_bitmap[register_index / 64] |=
1ull << (register_index % 64);
ParseAluInstructionOperandSpecial(op, InstructionStorageSource::kRegister,
reg2, op.src_negate(3), const_slot,
swiz_b, &i.operands[1]);
}
i.Disassemble(&ucode_disasm_buffer_);
ProcessAluInstruction(i);
}
} // namespace gpu

View File

@@ -27,8 +27,10 @@ class ShaderTranslator {
virtual ~ShaderTranslator();
// Gathers all vertex/texture bindings. Implicitly called in Translate.
// TODO: Move this functionality to Shader.
// DEPRECATED(benvanik): remove this when shader cache is removed.
bool GatherAllBindingInformation(Shader* shader);
bool Translate(Shader* shader, xenos::xe_gpu_program_cntl_t cntl);
bool Translate(Shader* shader);
protected:
@@ -37,6 +39,8 @@ class ShaderTranslator {
// Resets translator state before beginning translation.
virtual void Reset();
// Register count.
uint32_t register_count() const { return register_count_; }
// True if the current shader is a vertex shader.
bool is_vertex_shader() const { return shader_type_ == ShaderType::kVertex; }
// True if the current shader is a pixel shader.
@@ -70,6 +74,17 @@ class ShaderTranslator {
return std::vector<uint8_t>();
}
// Handles post-translation tasks when the shader has been fully translated.
virtual void PostTranslation(Shader* shader) {}
// Sets the host disassembly on a shader.
void set_host_disassembly(Shader* shader, std::string value) {
shader->host_disassembly_ = std::move(value);
}
// Pre-process a control-flow instruction before anything else.
virtual void PreProcessControlFlowInstruction(
uint32_t cf_index, const ucode::ControlFlowInstruction& instr) {}
// Handles translation for control flow label addresses.
// This is triggered once for each label required (due to control flow
// operations) before any of the instructions within the target exec.
@@ -120,6 +135,8 @@ class ShaderTranslator {
int src_swizzle_component_count;
};
bool TranslateInternal(Shader* shader);
void MarkUcodeInstruction(uint32_t dword_offset);
void AppendUcodeDisasm(char c);
void AppendUcodeDisasm(const char* value);
@@ -162,14 +179,18 @@ class ShaderTranslator {
void TranslateAluInstruction(const ucode::AluInstruction& op);
void ParseAluVectorInstruction(const ucode::AluInstruction& op,
const AluOpcodeInfo& opcode_info);
const AluOpcodeInfo& opcode_info,
ParsedAluInstruction& instr);
void ParseAluScalarInstruction(const ucode::AluInstruction& op,
const AluOpcodeInfo& opcode_info);
const AluOpcodeInfo& opcode_info,
ParsedAluInstruction& instr);
// Input shader metadata and microcode.
ShaderType shader_type_;
const uint32_t* ucode_dwords_;
size_t ucode_dword_count_;
xenos::xe_gpu_program_cntl_t program_cntl_;
uint32_t register_count_;
// Accumulated translation errors.
std::vector<Shader::Error> errors_;
@@ -191,6 +212,7 @@ class ShaderTranslator {
int total_attrib_count_ = 0;
std::vector<Shader::VertexBinding> vertex_bindings_;
std::vector<Shader::TextureBinding> texture_bindings_;
Shader::ConstantRegisterMap constant_register_map_ = {0};
bool writes_color_targets_[4] = {false, false, false, false};
static const AluOpcodeInfo alu_vector_opcode_infos_[0x20];

View File

@@ -0,0 +1,36 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2016 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "xenia/gpu/spirv/compiler.h"
namespace xe {
namespace gpu {
namespace spirv {
Compiler::Compiler() {}
void Compiler::AddPass(std::unique_ptr<CompilerPass> pass) {
compiler_passes_.push_back(std::move(pass));
}
bool Compiler::Compile(spv::Module* module) {
for (auto& pass : compiler_passes_) {
if (!pass->Run(module)) {
return false;
}
}
return true;
}
void Compiler::Reset() { compiler_passes_.clear(); }
} // namespace spirv
} // namespace gpu
} // namespace xe

View File

@@ -0,0 +1,41 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2016 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_GPU_SPIRV_COMPILER_H_
#define XENIA_GPU_SPIRV_COMPILER_H_
#include "xenia/base/arena.h"
#include "xenia/gpu/spirv/compiler_pass.h"
#include "third_party/glslang-spirv/SpvBuilder.h"
#include "third_party/spirv/GLSL.std.450.hpp11"
namespace xe {
namespace gpu {
namespace spirv {
// SPIR-V Compiler. Designed to optimize SPIR-V code before feeding it into the
// drivers.
class Compiler {
public:
Compiler();
void AddPass(std::unique_ptr<CompilerPass> pass);
void Reset();
bool Compile(spv::Module* module);
private:
std::vector<std::unique_ptr<CompilerPass>> compiler_passes_;
};
} // namespace spirv
} // namespace gpu
} // namespace xe
#endif // XENIA_GPU_SPIRV_COMPILER_H_

View File

@@ -0,0 +1,37 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2016 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_GPU_SPIRV_COMPILER_PASS_H_
#define XENIA_GPU_SPIRV_COMPILER_PASS_H_
#include "xenia/base/arena.h"
#include "third_party/glslang-spirv/SpvBuilder.h"
#include "third_party/spirv/GLSL.std.450.hpp11"
namespace xe {
namespace gpu {
namespace spirv {
class CompilerPass {
public:
CompilerPass() = default;
virtual ~CompilerPass() {}
virtual bool Run(spv::Module* module) = 0;
private:
xe::Arena ir_arena_;
};
} // namespace spirv
} // namespace gpu
} // namespace xe
#endif

View File

@@ -0,0 +1,30 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2016 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "xenia/gpu/spirv/passes/control_flow_analysis_pass.h"
namespace xe {
namespace gpu {
namespace spirv {
ControlFlowAnalysisPass::ControlFlowAnalysisPass() {}
bool ControlFlowAnalysisPass::Run(spv::Module* module) {
for (auto function : module->getFunctions()) {
// For each OpBranchConditional, see if we can find a point where control
// flow converges and then append an OpSelectionMerge.
// Potential problems: while loops constructed from branch instructions
}
return true;
}
} // namespace spirv
} // namespace gpu
} // namespace xe

View File

@@ -0,0 +1,34 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2016 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_GPU_SPIRV_PASSES_CONTROL_FLOW_ANALYSIS_PASS_H_
#define XENIA_GPU_SPIRV_PASSES_CONTROL_FLOW_ANALYSIS_PASS_H_
#include "xenia/gpu/spirv/compiler_pass.h"
namespace xe {
namespace gpu {
namespace spirv {
// Control-flow analysis pass. Runs through control-flow and adds merge opcodes
// where necessary.
class ControlFlowAnalysisPass : public CompilerPass {
public:
ControlFlowAnalysisPass();
bool Run(spv::Module* module) override;
private:
};
} // namespace spirv
} // namespace gpu
} // namespace xe
#endif // XENIA_GPU_SPIRV_PASSES_CONTROL_FLOW_ANALYSIS_PASS_H_

View File

@@ -0,0 +1,48 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2016 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "xenia/gpu/spirv/passes/control_flow_simplification_pass.h"
namespace xe {
namespace gpu {
namespace spirv {
ControlFlowSimplificationPass::ControlFlowSimplificationPass() {}
bool ControlFlowSimplificationPass::Run(spv::Module* module) {
for (auto function : module->getFunctions()) {
// Walk through the blocks in the function and merge any blocks which are
// unconditionally dominated.
for (auto it = function->getBlocks().end() - 1;
it != function->getBlocks().begin() - 1;) {
auto block = *it;
if (!block->isUnreachable() && block->getPredecessors().size() == 1) {
auto prev_block = block->getPredecessors()[0];
auto last_instr =
prev_block->getInstruction(prev_block->getInstructionCount() - 1);
if (last_instr->getOpCode() == spv::Op::OpBranch) {
if (prev_block->getSuccessors().size() == 1 &&
prev_block->getSuccessors()[0] == block) {
// We're dominated by this block. Merge into it.
prev_block->merge(block);
block->setUnreachable();
}
}
}
--it;
}
}
return true;
}
} // namespace spirv
} // namespace gpu
} // namespace xe

View File

@@ -0,0 +1,34 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2016 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_GPU_SPIRV_PASSES_CONTROL_FLOW_SIMPLIFICATION_PASS_H_
#define XENIA_GPU_SPIRV_PASSES_CONTROL_FLOW_SIMPLIFICATION_PASS_H_
#include "xenia/gpu/spirv/compiler_pass.h"
namespace xe {
namespace gpu {
namespace spirv {
// Control-flow simplification pass. Combines adjacent blocks and marks
// any unreachable blocks.
class ControlFlowSimplificationPass : public CompilerPass {
public:
ControlFlowSimplificationPass();
bool Run(spv::Module* module) override;
private:
};
} // namespace spirv
} // namespace gpu
} // namespace xe
#endif // XENIA_GPU_SPIRV_PASSES_CONTROL_FLOW_SIMPLIFICATION_PASS_H_

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2015 Ben Vanik. All rights reserved. *
* Copyright 2016 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@@ -14,12 +14,38 @@
#include <string>
#include <vector>
#include "third_party/glslang-spirv/SpvBuilder.h"
#include "third_party/spirv/GLSL.std.450.hpp11"
#include "xenia/gpu/shader_translator.h"
#include "xenia/ui/spirv/spirv_emitter.h"
#include "xenia/gpu/spirv/compiler.h"
#include "xenia/ui/spirv/spirv_disassembler.h"
#include "xenia/ui/spirv/spirv_validator.h"
namespace xe {
namespace gpu {
// Push constants embedded within the command buffer.
// The total size of this struct must be <= 128b (as that's the commonly
// supported size).
struct SpirvPushConstants {
// Accessible to vertex shader only:
float window_scale[4]; // sx,sy, ?, ?
float vtx_fmt[4];
// Accessible to fragment shader only:
float alpha_test[4]; // alpha test enable, func, ref, ?
uint32_t ps_param_gen;
};
static_assert(sizeof(SpirvPushConstants) <= 128,
"Push constants must fit <= 128b");
constexpr uint32_t kSpirvPushConstantVertexRangeOffset = 0;
constexpr uint32_t kSpirvPushConstantVertexRangeSize = (sizeof(float) * 4) * 2;
constexpr uint32_t kSpirvPushConstantFragmentRangeOffset =
kSpirvPushConstantVertexRangeSize;
constexpr uint32_t kSpirvPushConstantFragmentRangeSize =
(sizeof(float) * 4) + sizeof(uint32_t);
constexpr uint32_t kSpirvPushConstantsSize = sizeof(SpirvPushConstants);
class SpirvShaderTranslator : public ShaderTranslator {
public:
SpirvShaderTranslator();
@@ -28,8 +54,13 @@ class SpirvShaderTranslator : public ShaderTranslator {
protected:
void StartTranslation() override;
std::vector<uint8_t> CompleteTranslation() override;
void PostTranslation(Shader* shader) override;
void PreProcessControlFlowInstruction(
uint32_t cf_index, const ucode::ControlFlowInstruction& instr) override;
void ProcessLabel(uint32_t cf_index) override;
void ProcessControlFlowInstructionBegin(uint32_t cf_index) override;
void ProcessControlFlowInstructionEnd(uint32_t cf_index) override;
void ProcessControlFlowNopInstruction() override;
void ProcessExecInstructionBegin(const ParsedExecInstruction& instr) override;
void ProcessExecInstructionEnd(const ParsedExecInstruction& instr) override;
@@ -51,6 +82,11 @@ class SpirvShaderTranslator : public ShaderTranslator {
void ProcessVectorAluInstruction(const ParsedAluInstruction& instr);
void ProcessScalarAluInstruction(const ParsedAluInstruction& instr);
// Creates a call to the given GLSL intrinsic.
spv::Id SpirvShaderTranslator::CreateGlslStd450InstructionCall(
spv::Decoration precision, spv::Id result_type,
spv::GLSLstd450 instruction_ordinal, std::vector<spv::Id> args);
// Loads an operand into a value.
// The value returned will be in the form described in the operand (number of
// components, etc).
@@ -60,7 +96,52 @@ class SpirvShaderTranslator : public ShaderTranslator {
// the proper components will be selected.
void StoreToResult(spv::Id source_value_id, const InstructionResult& result);
xe::ui::spirv::SpirvEmitter emitter_;
xe::ui::spirv::SpirvDisassembler disassembler_;
xe::ui::spirv::SpirvValidator validator_;
xe::gpu::spirv::Compiler compiler_;
// True if there's an open predicated block
bool open_predicated_block_ = false;
bool predicated_block_cond_ = false;
spv::Block* predicated_block_end_ = nullptr;
// TODO(benvanik): replace with something better, make reusable, etc.
std::unique_ptr<spv::Builder> builder_;
spv::Id glsl_std_450_instruction_set_ = 0;
// Generated function
spv::Function* translated_main_ = 0;
// Types.
spv::Id float_type_ = 0, bool_type_ = 0, int_type_ = 0, uint_type_ = 0;
spv::Id vec2_float_type_ = 0, vec3_float_type_ = 0, vec4_float_type_ = 0;
spv::Id vec4_uint_type_ = 0;
spv::Id vec4_bool_type_ = 0;
// Constants.
spv::Id vec4_float_zero_ = 0, vec4_float_one_ = 0;
// Array of AMD registers.
// These values are all pointers.
spv::Id registers_ptr_ = 0, registers_type_ = 0;
spv::Id consts_ = 0, a0_ = 0, aL_ = 0, p0_ = 0;
spv::Id ps_ = 0, pv_ = 0; // IDs of previous results
spv::Id pos_ = 0;
spv::Id push_consts_ = 0;
spv::Id interpolators_ = 0;
spv::Id vertex_id_ = 0;
spv::Id frag_outputs_ = 0, frag_depth_ = 0;
spv::Id samplers_ = 0;
spv::Id tex_[4] = {0}; // Images {1D, 2D, 3D, Cube}
// Map of {binding -> {offset -> spv input}}
std::map<uint32_t, std::map<uint32_t, spv::Id>> vertex_binding_map_;
struct CFBlock {
spv::Block* block = nullptr;
bool prev_dominates = true;
};
std::map<uint32_t, CFBlock> cf_blocks_;
};
} // namespace gpu

View File

@@ -88,6 +88,66 @@ enum class TextureFormat : uint32_t {
kUnknown = 0xFFFFFFFFu,
};
inline size_t GetTexelSize(TextureFormat format) {
switch (format) {
case TextureFormat::k_1_5_5_5:
return 2;
break;
case TextureFormat::k_2_10_10_10:
return 4;
break;
case TextureFormat::k_4_4_4_4:
return 2;
break;
case TextureFormat::k_5_6_5:
return 2;
break;
case TextureFormat::k_8:
return 1;
break;
case TextureFormat::k_8_8:
return 2;
break;
case TextureFormat::k_8_8_8_8:
return 4;
break;
case TextureFormat::k_16:
return 4;
break;
case TextureFormat::k_16_FLOAT:
return 4;
break;
case TextureFormat::k_16_16:
return 4;
break;
case TextureFormat::k_16_16_FLOAT:
return 4;
break;
case TextureFormat::k_16_16_16_16:
return 8;
break;
case TextureFormat::k_16_16_16_16_FLOAT:
return 8;
break;
case TextureFormat::k_32_FLOAT:
return 4;
break;
case TextureFormat::k_32_32_FLOAT:
return 8;
break;
case TextureFormat::k_32_32_32_32_FLOAT:
return 16;
break;
case TextureFormat::k_10_11_11:
case TextureFormat::k_11_11_10:
return 4;
break;
default:
assert_unhandled_case(format);
return 0;
}
}
inline TextureFormat ColorFormatToTextureFormat(ColorFormat color_format) {
return static_cast<TextureFormat>(color_format);
}

View File

@@ -13,6 +13,7 @@
#include "third_party/stb/stb_image_write.h"
#include "xenia/base/logging.h"
#include "xenia/base/profiling.h"
#include "xenia/base/string.h"
#include "xenia/base/threading.h"
#include "xenia/gpu/command_processor.h"
@@ -189,10 +190,16 @@ void TraceDump::Run() {
});
xe::threading::Fence capture_fence;
bool did_capture = false;
loop_->PostDelayed(
[&]() {
// Capture.
auto raw_image = window_->context()->Capture();
if (!raw_image) {
// Failed to capture anything.
capture_fence.Signal();
return;
}
// Save framebuffer png.
std::string png_path = xe::to_string(base_output_path_ + L".png");
@@ -201,6 +208,7 @@ void TraceDump::Run() {
raw_image->data.data(),
static_cast<int>(raw_image->stride));
did_capture = true;
capture_fence.Signal();
},
50);
@@ -211,10 +219,13 @@ void TraceDump::Run() {
loop_->Quit();
loop_->AwaitQuit();
player_.reset();
emulator_.reset();
Profiler::Shutdown();
window_.reset();
loop_.reset();
player_.reset();
emulator_.reset();
// TODO(benvanik): die if failed to capture?
}
} // namespace gpu

View File

@@ -51,7 +51,7 @@ void TracePlayer::SeekFrame(int target_frame) {
assert_true(frame->start_ptr <= frame->end_ptr);
PlayTrace(frame->start_ptr, frame->end_ptr - frame->start_ptr,
TracePlaybackMode::kBreakOnSwap);
TracePlaybackMode::kBreakOnSwap, false);
}
void TracePlayer::SeekCommand(int target_command) {
@@ -71,11 +71,11 @@ void TracePlayer::SeekCommand(int target_command) {
const auto& previous_command = frame->commands[previous_command_index];
PlayTrace(previous_command.end_ptr,
command.end_ptr - previous_command.end_ptr,
TracePlaybackMode::kBreakOnSwap);
TracePlaybackMode::kBreakOnSwap, false);
} else {
// Full playback from frame start.
PlayTrace(frame->start_ptr, command.end_ptr - frame->start_ptr,
TracePlaybackMode::kBreakOnSwap);
TracePlaybackMode::kBreakOnSwap, true);
}
}
@@ -84,19 +84,25 @@ void TracePlayer::WaitOnPlayback() {
}
void TracePlayer::PlayTrace(const uint8_t* trace_data, size_t trace_size,
TracePlaybackMode playback_mode) {
graphics_system_->command_processor()->CallInThread(
[this, trace_data, trace_size, playback_mode]() {
PlayTraceOnThread(trace_data, trace_size, playback_mode);
});
TracePlaybackMode playback_mode,
bool clear_caches) {
playing_trace_ = true;
graphics_system_->command_processor()->CallInThread([=]() {
PlayTraceOnThread(trace_data, trace_size, playback_mode, clear_caches);
});
}
void TracePlayer::PlayTraceOnThread(const uint8_t* trace_data,
size_t trace_size,
TracePlaybackMode playback_mode) {
TracePlaybackMode playback_mode,
bool clear_caches) {
auto memory = graphics_system_->memory();
auto command_processor = graphics_system_->command_processor();
if (clear_caches) {
command_processor->ClearCaches();
}
command_processor->set_swap_mode(SwapMode::kIgnored);
playback_percent_ = 0;
auto trace_end = trace_data + trace_size;

View File

@@ -50,9 +50,9 @@ class TracePlayer : public TraceReader {
private:
void PlayTrace(const uint8_t* trace_data, size_t trace_size,
TracePlaybackMode playback_mode);
TracePlaybackMode playback_mode, bool clear_caches);
void PlayTraceOnThread(const uint8_t* trace_data, size_t trace_size,
TracePlaybackMode playback_mode);
TracePlaybackMode playback_mode, bool clear_caches);
xe::ui::Loop* loop_;
GraphicsSystem* graphics_system_;

View File

@@ -75,6 +75,10 @@ void TraceReader::ParseTrace() {
const uint8_t* packet_start_ptr = nullptr;
const uint8_t* last_ptr = trace_ptr;
bool pending_break = false;
auto current_command_buffer = new CommandBuffer();
current_frame.command_tree =
std::unique_ptr<CommandBuffer>(current_command_buffer);
while (trace_ptr < trace_data_ + trace_size_) {
++current_frame.command_count;
auto type = static_cast<TraceCommandType>(xe::load<uint32_t>(trace_ptr));
@@ -94,11 +98,29 @@ void TraceReader::ParseTrace() {
auto cmd =
reinterpret_cast<const IndirectBufferStartCommand*>(trace_ptr);
trace_ptr += sizeof(*cmd) + cmd->count * 4;
// Traverse down a level.
auto sub_command_buffer = new CommandBuffer();
sub_command_buffer->parent = current_command_buffer;
current_command_buffer->commands.push_back(
CommandBuffer::Command(sub_command_buffer));
current_command_buffer = sub_command_buffer;
break;
}
case TraceCommandType::kIndirectBufferEnd: {
auto cmd = reinterpret_cast<const IndirectBufferEndCommand*>(trace_ptr);
trace_ptr += sizeof(*cmd);
// IB packet is wrapped in a kPacketStart/kPacketEnd. Skip the end.
auto end_cmd = reinterpret_cast<const PacketEndCommand*>(trace_ptr);
assert_true(end_cmd->type == TraceCommandType::kPacketEnd);
trace_ptr += sizeof(*cmd);
// Go back up a level. If parent is null, this frame started in an
// indirect buffer.
if (current_command_buffer->parent) {
current_command_buffer = current_command_buffer->parent;
}
break;
}
case TraceCommandType::kPacketStart: {
@@ -125,6 +147,8 @@ void TraceReader::ParseTrace() {
command.end_ptr = trace_ptr;
current_frame.commands.push_back(std::move(command));
last_ptr = trace_ptr;
current_command_buffer->commands.push_back(CommandBuffer::Command(
uint32_t(current_frame.commands.size() - 1)));
break;
}
case PacketCategory::kSwap:
@@ -136,6 +160,9 @@ void TraceReader::ParseTrace() {
if (pending_break) {
current_frame.end_ptr = trace_ptr;
frames_.push_back(std::move(current_frame));
current_command_buffer = new CommandBuffer();
current_frame.command_tree =
std::unique_ptr<CommandBuffer>(current_command_buffer);
current_frame.start_ptr = trace_ptr;
current_frame.end_ptr = nullptr;
current_frame.command_count = 0;

View File

@@ -11,6 +11,7 @@
#define XENIA_GPU_TRACE_READER_H_
#include <string>
#include <vector>
#include "xenia/base/mapped_memory.h"
#include "xenia/gpu/trace_protocol.h"
@@ -51,6 +52,42 @@ namespace gpu {
class TraceReader {
public:
struct CommandBuffer {
struct Command {
enum class Type {
kCommand,
kBuffer,
};
Command() {}
Command(Command&& other) {
type = other.type;
command_id = other.command_id;
command_subtree = std::move(other.command_subtree);
}
Command(CommandBuffer* buf) {
type = Type::kBuffer;
command_subtree = std::unique_ptr<CommandBuffer>(buf);
}
Command(uint32_t id) {
type = Type::kCommand;
command_id = id;
}
~Command() = default;
Type type;
uint32_t command_id = -1;
std::unique_ptr<CommandBuffer> command_subtree = nullptr;
};
CommandBuffer() {}
~CommandBuffer() {}
// Parent command buffer, if one exists.
CommandBuffer* parent = nullptr;
std::vector<Command> commands;
};
struct Frame {
struct Command {
enum class Type {
@@ -74,7 +111,12 @@ class TraceReader {
const uint8_t* start_ptr = nullptr;
const uint8_t* end_ptr = nullptr;
int command_count = 0;
// Flat list of all commands in this frame.
std::vector<Command> commands;
// Tree of all command buffers
std::unique_ptr<CommandBuffer> command_tree;
};
TraceReader() = default;

View File

@@ -390,6 +390,66 @@ void TraceViewer::DrawPacketDisassemblerUI() {
ImGui::End();
}
int TraceViewer::RecursiveDrawCommandBufferUI(
const TraceReader::Frame* frame, TraceReader::CommandBuffer* buffer) {
int selected_id = -1;
int column_width = int(ImGui::GetContentRegionMax().x);
for (size_t i = 0; i < buffer->commands.size(); i++) {
switch (buffer->commands[i].type) {
case TraceReader::CommandBuffer::Command::Type::kBuffer: {
auto subtree = buffer->commands[i].command_subtree.get();
if (!subtree->commands.size()) {
continue;
}
ImGui::PushID(int(i));
if (ImGui::TreeNode((void*)0, "Indirect Buffer %d", i)) {
ImGui::Indent();
auto id = RecursiveDrawCommandBufferUI(
frame, buffer->commands[i].command_subtree.get());
ImGui::Unindent();
ImGui::TreePop();
if (id != -1) {
selected_id = id;
}
}
ImGui::PopID();
} break;
case TraceReader::CommandBuffer::Command::Type::kCommand: {
uint32_t command_id = buffer->commands[i].command_id;
const auto& command = frame->commands[command_id];
bool is_selected = command_id == player_->current_command_index();
const char* label;
switch (command.type) {
case TraceReader::Frame::Command::Type::kDraw:
label = "Draw";
break;
case TraceReader::Frame::Command::Type::kSwap:
label = "Swap";
break;
}
ImGui::PushID(command_id);
if (ImGui::Selectable(label, &is_selected)) {
selected_id = command_id;
}
ImGui::SameLine(column_width - 60.0f);
ImGui::Text("%d", command_id);
ImGui::PopID();
// if (did_seek && target_command == i) {
// ImGui::SetScrollPosHere();
// }
} break;
}
}
return selected_id;
}
void TraceViewer::DrawCommandListUI() {
ImGui::SetNextWindowPos(ImVec2(5, 70), ImGuiSetCond_FirstUseEver);
if (!ImGui::Begin("Command List", nullptr, ImVec2(200, 640))) {
@@ -473,31 +533,12 @@ void TraceViewer::DrawCommandListUI() {
ImGui::SetScrollPosHere();
}
for (int i = 0; i < int(frame->commands.size()); ++i) {
ImGui::PushID(i);
is_selected = i == player_->current_command_index();
const auto& command = frame->commands[i];
const char* label;
switch (command.type) {
case TraceReader::Frame::Command::Type::kDraw:
label = "Draw";
break;
case TraceReader::Frame::Command::Type::kSwap:
label = "Swap";
break;
}
if (ImGui::Selectable(label, &is_selected)) {
if (!player_->is_playing_trace()) {
player_->SeekCommand(i);
}
}
ImGui::SameLine(column_width - 60.0f);
ImGui::Text("%d", i);
ImGui::PopID();
if (did_seek && target_command == i) {
ImGui::SetScrollPosHere();
}
auto id = RecursiveDrawCommandBufferUI(frame, frame->command_tree.get());
if (id != -1 && id != player_->current_command_index() &&
!player_->is_playing_trace()) {
player_->SeekCommand(id);
}
ImGui::EndChild();
ImGui::End();
}
@@ -639,8 +680,8 @@ void TraceViewer::DrawTextureInfo(
ImGui::Columns(2);
ImVec2 button_size(256, 256);
if (ImGui::ImageButton(ImTextureID(texture | ui::ImGuiDrawer::kIgnoreAlpha),
button_size, ImVec2(0, 0), ImVec2(1, 1))) {
if (ImGui::ImageButton(ImTextureID(texture), button_size, ImVec2(0, 0),
ImVec2(1, 1))) {
// show viewer
}
ImGui::NextColumn();
@@ -1108,11 +1149,14 @@ void TraceViewer::DrawStateUI() {
((window_scissor_br >> 16) & 0x7FFF) -
((window_scissor_tl >> 16) & 0x7FFF));
uint32_t surface_info = regs[XE_GPU_REG_RB_SURFACE_INFO].u32;
uint32_t surface_actual = (surface_info >> 18) & 0x3FFF;
uint32_t surface_pitch = surface_info & 0x3FFF;
auto surface_msaa = (surface_info >> 16) & 0x3;
static const char* kMsaaNames[] = {
"1X", "2X", "4X",
};
ImGui::BulletText("Surface Pitch - Actual: %d - %d", surface_pitch,
surface_actual);
ImGui::BulletText("Surface MSAA: %s", kMsaaNames[surface_msaa]);
uint32_t vte_control = regs[XE_GPU_REG_PA_CL_VTE_CNTL].u32;
bool vport_xscale_enable = (vte_control & (1 << 0)) > 0;
@@ -1124,6 +1168,9 @@ void TraceViewer::DrawStateUI() {
assert_true(vport_xscale_enable == vport_yscale_enable ==
vport_zscale_enable == vport_xoffset_enable ==
vport_yoffset_enable == vport_zoffset_enable);
if (!vport_xscale_enable) {
ImGui::PushStyleColor(ImGuiCol_Text, kColorIgnored);
}
ImGui::BulletText(
"Viewport Offset: %f, %f, %f",
vport_xoffset_enable ? regs[XE_GPU_REG_PA_CL_VPORT_XOFFSET].f32 : 0,
@@ -1134,6 +1181,10 @@ void TraceViewer::DrawStateUI() {
vport_xscale_enable ? regs[XE_GPU_REG_PA_CL_VPORT_XSCALE].f32 : 1,
vport_yscale_enable ? regs[XE_GPU_REG_PA_CL_VPORT_YSCALE].f32 : 1,
vport_zscale_enable ? regs[XE_GPU_REG_PA_CL_VPORT_ZSCALE].f32 : 1);
if (!vport_xscale_enable) {
ImGui::PopStyleColor();
}
ImGui::BulletText("Vertex Format: %s, %s, %s, %s",
((vte_control >> 8) & 0x1) ? "x/w0" : "x",
((vte_control >> 8) & 0x1) ? "y/w0" : "y",
@@ -1318,7 +1369,7 @@ void TraceViewer::DrawStateUI() {
if (write_mask) {
auto color_target = GetColorRenderTarget(surface_pitch, surface_msaa,
color_base, color_format);
tex = ImTextureID(color_target | ui::ImGuiDrawer::kIgnoreAlpha);
tex = ImTextureID(color_target);
if (ImGui::ImageButton(tex, button_size, ImVec2(0, 0),
ImVec2(1, 1))) {
// show viewer
@@ -1330,10 +1381,9 @@ void TraceViewer::DrawStateUI() {
}
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
ImGui::Text(
"Color Target %d (%s), base %.4X, pitch %d, msaa %d, format %d",
i, write_mask ? "enabled" : "disabled", color_base, surface_pitch,
surface_msaa, color_format);
ImGui::Text("Color Target %d (%s), base %.4X, pitch %d, format %d", i,
write_mask ? "enabled" : "disabled", color_base,
surface_pitch, color_format);
if (tex) {
ImVec2 rel_pos;
@@ -1407,17 +1457,19 @@ void TraceViewer::DrawStateUI() {
auto button_pos = ImGui::GetCursorScreenPos();
ImVec2 button_size(256, 256);
ImGui::ImageButton(
ImTextureID(depth_target | ui::ImGuiDrawer::kIgnoreAlpha),
button_size, ImVec2(0, 0), ImVec2(1, 1));
ImGui::ImageButton(ImTextureID(depth_target), button_size, ImVec2(0, 0),
ImVec2(1, 1));
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
ImGui::Text("Depth Target: base %.4X, pitch %d, format %d", depth_base,
surface_pitch, depth_format);
ImVec2 rel_pos;
rel_pos.x = ImGui::GetMousePos().x - button_pos.x;
rel_pos.y = ImGui::GetMousePos().y - button_pos.y;
ZoomedImage(ImTextureID(depth_target | ui::ImGuiDrawer::kIgnoreAlpha),
rel_pos, button_size, 32.f, ImVec2(256, 256));
ZoomedImage(ImTextureID(depth_target), rel_pos, button_size, 32.f,
ImVec2(256, 256));
ImGui::EndTooltip();
}
@@ -1439,7 +1491,8 @@ void TraceViewer::DrawStateUI() {
}
ImGui::EndChild();
}
if (ImGui::CollapsingHeader("Vertex Shader Output")) {
if (ImGui::CollapsingHeader("Vertex Shader Output") &&
QueryVSOutputElementSize()) {
auto size = QueryVSOutputSize();
auto el_size = QueryVSOutputElementSize();
if (size > 0) {

View File

@@ -54,9 +54,9 @@ class TraceViewer {
virtual uintptr_t GetTextureEntry(const TextureInfo& texture_info,
const SamplerInfo& sampler_info) = 0;
virtual size_t QueryVSOutputSize() = 0;
virtual size_t QueryVSOutputElementSize() = 0;
virtual bool QueryVSOutput(void* buffer, size_t size) = 0;
virtual size_t QueryVSOutputSize() { return 0; }
virtual size_t QueryVSOutputElementSize() { return 0; }
virtual bool QueryVSOutput(void* buffer, size_t size) { return false; }
virtual bool Setup();
@@ -80,6 +80,8 @@ class TraceViewer {
void DrawUI();
void DrawControllerUI();
void DrawPacketDisassemblerUI();
int RecursiveDrawCommandBufferUI(const TraceReader::Frame* frame,
TraceReader::CommandBuffer* buffer);
void DrawCommandListUI();
void DrawStateUI();

View File

@@ -0,0 +1,334 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2016 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "xenia/gpu/vulkan/buffer_cache.h"
#include "xenia/base/logging.h"
#include "xenia/base/math.h"
#include "xenia/base/memory.h"
#include "xenia/base/profiling.h"
#include "xenia/gpu/gpu_flags.h"
#include "xenia/gpu/vulkan/vulkan_gpu_flags.h"
namespace xe {
namespace gpu {
namespace vulkan {
using xe::ui::vulkan::CheckResult;
constexpr VkDeviceSize kConstantRegisterUniformRange =
512 * 4 * 4 + 8 * 4 + 32 * 4;
BufferCache::BufferCache(RegisterFile* register_file,
ui::vulkan::VulkanDevice* device, size_t capacity)
: register_file_(register_file), device_(*device) {
transient_buffer_ = std::make_unique<ui::vulkan::CircularBuffer>(device);
if (!transient_buffer_->Initialize(capacity,
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT |
VK_BUFFER_USAGE_INDEX_BUFFER_BIT |
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT)) {
assert_always();
}
// Descriptor pool used for all of our cached descriptors.
// In the steady state we don't allocate anything, so these are all manually
// managed.
VkDescriptorPoolCreateInfo descriptor_pool_info;
descriptor_pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
descriptor_pool_info.pNext = nullptr;
descriptor_pool_info.flags =
VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
descriptor_pool_info.maxSets = 1;
VkDescriptorPoolSize pool_sizes[1];
pool_sizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
pool_sizes[0].descriptorCount = 2;
descriptor_pool_info.poolSizeCount = 1;
descriptor_pool_info.pPoolSizes = pool_sizes;
auto err = vkCreateDescriptorPool(device_, &descriptor_pool_info, nullptr,
&descriptor_pool_);
CheckResult(err, "vkCreateDescriptorPool");
// Create the descriptor set layout used for our uniform buffer.
// As it is a static binding that uses dynamic offsets during draws we can
// create this once and reuse it forever.
VkDescriptorSetLayoutBinding vertex_uniform_binding;
vertex_uniform_binding.binding = 0;
vertex_uniform_binding.descriptorType =
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
vertex_uniform_binding.descriptorCount = 1;
vertex_uniform_binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
vertex_uniform_binding.pImmutableSamplers = nullptr;
VkDescriptorSetLayoutBinding fragment_uniform_binding;
fragment_uniform_binding.binding = 1;
fragment_uniform_binding.descriptorType =
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
fragment_uniform_binding.descriptorCount = 1;
fragment_uniform_binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
fragment_uniform_binding.pImmutableSamplers = nullptr;
VkDescriptorSetLayoutCreateInfo descriptor_set_layout_info;
descriptor_set_layout_info.sType =
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
descriptor_set_layout_info.pNext = nullptr;
descriptor_set_layout_info.flags = 0;
VkDescriptorSetLayoutBinding uniform_bindings[] = {
vertex_uniform_binding, fragment_uniform_binding,
};
descriptor_set_layout_info.bindingCount =
static_cast<uint32_t>(xe::countof(uniform_bindings));
descriptor_set_layout_info.pBindings = uniform_bindings;
err = vkCreateDescriptorSetLayout(device_, &descriptor_set_layout_info,
nullptr, &descriptor_set_layout_);
CheckResult(err, "vkCreateDescriptorSetLayout");
// Create the descriptor we'll use for the uniform buffer.
// This is what we hand out to everyone (who then also needs to use our
// offsets).
VkDescriptorSetAllocateInfo set_alloc_info;
set_alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
set_alloc_info.pNext = nullptr;
set_alloc_info.descriptorPool = descriptor_pool_;
set_alloc_info.descriptorSetCount = 1;
set_alloc_info.pSetLayouts = &descriptor_set_layout_;
err = vkAllocateDescriptorSets(device_, &set_alloc_info,
&transient_descriptor_set_);
CheckResult(err, "vkAllocateDescriptorSets");
// Initialize descriptor set with our buffers.
VkDescriptorBufferInfo buffer_info;
buffer_info.buffer = transient_buffer_->gpu_buffer();
buffer_info.offset = 0;
buffer_info.range = kConstantRegisterUniformRange;
VkWriteDescriptorSet descriptor_writes[2];
auto& vertex_uniform_binding_write = descriptor_writes[0];
vertex_uniform_binding_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
vertex_uniform_binding_write.pNext = nullptr;
vertex_uniform_binding_write.dstSet = transient_descriptor_set_;
vertex_uniform_binding_write.dstBinding = 0;
vertex_uniform_binding_write.dstArrayElement = 0;
vertex_uniform_binding_write.descriptorCount = 1;
vertex_uniform_binding_write.descriptorType =
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
vertex_uniform_binding_write.pBufferInfo = &buffer_info;
auto& fragment_uniform_binding_write = descriptor_writes[1];
fragment_uniform_binding_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
fragment_uniform_binding_write.pNext = nullptr;
fragment_uniform_binding_write.dstSet = transient_descriptor_set_;
fragment_uniform_binding_write.dstBinding = 1;
fragment_uniform_binding_write.dstArrayElement = 0;
fragment_uniform_binding_write.descriptorCount = 1;
fragment_uniform_binding_write.descriptorType =
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
fragment_uniform_binding_write.pBufferInfo = &buffer_info;
vkUpdateDescriptorSets(device_, 2, descriptor_writes, 0, nullptr);
}
BufferCache::~BufferCache() {
vkFreeDescriptorSets(device_, descriptor_pool_, 1,
&transient_descriptor_set_);
vkDestroyDescriptorSetLayout(device_, descriptor_set_layout_, nullptr);
vkDestroyDescriptorPool(device_, descriptor_pool_, nullptr);
transient_buffer_->Shutdown();
}
std::pair<VkDeviceSize, VkDeviceSize> BufferCache::UploadConstantRegisters(
const Shader::ConstantRegisterMap& vertex_constant_register_map,
const Shader::ConstantRegisterMap& pixel_constant_register_map,
std::shared_ptr<ui::vulkan::Fence> fence) {
// Fat struct, including all registers:
// struct {
// vec4 float[512];
// uint bool[8];
// uint loop[32];
// };
auto offset = AllocateTransientData(kConstantRegisterUniformRange, fence);
if (offset == VK_WHOLE_SIZE) {
// OOM.
return {VK_WHOLE_SIZE, VK_WHOLE_SIZE};
}
// Copy over all the registers.
const auto& values = register_file_->values;
uint8_t* dest_ptr = transient_buffer_->host_base() + offset;
std::memcpy(dest_ptr, &values[XE_GPU_REG_SHADER_CONSTANT_000_X].f32,
(512 * 4 * 4));
dest_ptr += 512 * 4 * 4;
std::memcpy(dest_ptr, &values[XE_GPU_REG_SHADER_CONSTANT_BOOL_000_031].u32,
8 * 4);
dest_ptr += 8 * 4;
std::memcpy(dest_ptr, &values[XE_GPU_REG_SHADER_CONSTANT_LOOP_00].u32,
32 * 4);
dest_ptr += 32 * 4;
return {offset, offset};
// Packed upload code.
// This is not currently supported by the shaders, but would be awesome.
// We should be able to use this for any shader that does not do dynamic
// constant indexing.
#if 0
// Allocate space in the buffer for our data.
auto offset =
AllocateTransientData(constant_register_map.packed_byte_length, fence);
if (offset == VK_WHOLE_SIZE) {
// OOM.
return VK_WHOLE_SIZE;
}
// Run through registers and copy them into the buffer.
// TODO(benvanik): optimize this - it's hit twice every call.
const auto& values = register_file_->values;
uint8_t* dest_ptr =
reinterpret_cast<uint8_t*>(transient_buffer_data_) + offset;
for (int i = 0; i < 4; ++i) {
auto piece = constant_register_map.float_bitmap[i];
if (!piece) {
continue;
}
for (int j = 0, sh = 0; j < 64; ++j, sh << 1) {
if (piece & sh) {
xe::copy_128_aligned(
dest_ptr,
&values[XE_GPU_REG_SHADER_CONSTANT_000_X + i * 64 + j].f32, 1);
dest_ptr += 16;
}
}
}
for (int i = 0; i < 32; ++i) {
if (constant_register_map.int_bitmap & (1 << i)) {
xe::store<uint32_t>(dest_ptr,
values[XE_GPU_REG_SHADER_CONSTANT_LOOP_00 + i].u32);
dest_ptr += 4;
}
}
for (int i = 0; i < 8; ++i) {
if (constant_register_map.bool_bitmap[i]) {
xe::store<uint32_t>(
dest_ptr, values[XE_GPU_REG_SHADER_CONSTANT_BOOL_000_031 + i].u32);
dest_ptr += 4;
}
}
return offset;
#endif // 0
}
std::pair<VkBuffer, VkDeviceSize> BufferCache::UploadIndexBuffer(
const void* source_ptr, size_t source_length, IndexFormat format,
std::shared_ptr<ui::vulkan::Fence> fence) {
// TODO(benvanik): check cache.
// Allocate space in the buffer for our data.
auto offset = AllocateTransientData(source_length, fence);
if (offset == VK_WHOLE_SIZE) {
// OOM.
return {nullptr, VK_WHOLE_SIZE};
}
// Copy data into the buffer.
// TODO(benvanik): get min/max indices and pass back?
// TODO(benvanik): memcpy then use compute shaders to swap?
if (format == IndexFormat::kInt16) {
// Endian::k8in16, swap half-words.
xe::copy_and_swap_16_aligned(transient_buffer_->host_base() + offset,
source_ptr, source_length / 2);
} else if (format == IndexFormat::kInt32) {
// Endian::k8in32, swap words.
xe::copy_and_swap_32_aligned(transient_buffer_->host_base() + offset,
source_ptr, source_length / 4);
}
return {transient_buffer_->gpu_buffer(), offset};
}
std::pair<VkBuffer, VkDeviceSize> BufferCache::UploadVertexBuffer(
const void* source_ptr, size_t source_length, Endian endian,
std::shared_ptr<ui::vulkan::Fence> fence) {
// TODO(benvanik): check cache.
// Allocate space in the buffer for our data.
auto offset = AllocateTransientData(source_length, fence);
if (offset == VK_WHOLE_SIZE) {
// OOM.
return {nullptr, VK_WHOLE_SIZE};
}
// Copy data into the buffer.
// TODO(benvanik): memcpy then use compute shaders to swap?
assert_true(endian == Endian::k8in32);
if (endian == Endian::k8in32) {
// Endian::k8in32, swap words.
xe::copy_and_swap_32_aligned(transient_buffer_->host_base() + offset,
source_ptr, source_length / 4);
}
return {transient_buffer_->gpu_buffer(), offset};
}
VkDeviceSize BufferCache::AllocateTransientData(
VkDeviceSize length, std::shared_ptr<ui::vulkan::Fence> fence) {
// Try fast path (if we have space).
VkDeviceSize offset = TryAllocateTransientData(length, fence);
if (offset != VK_WHOLE_SIZE) {
return offset;
}
// Ran out of easy allocations.
// Try consuming fences before we panic.
transient_buffer_->Scavenge();
// Try again. It may still fail if we didn't get enough space back.
offset = TryAllocateTransientData(length, fence);
return offset;
}
VkDeviceSize BufferCache::TryAllocateTransientData(
VkDeviceSize length, std::shared_ptr<ui::vulkan::Fence> fence) {
auto alloc = transient_buffer_->Acquire(length, fence);
if (alloc) {
return alloc->offset;
}
// No more space.
return VK_WHOLE_SIZE;
}
void BufferCache::Flush(VkCommandBuffer command_buffer) {
// If we are flushing a big enough chunk queue up an event.
// We don't want to do this for everything but often enough so that we won't
// run out of space.
if (true) {
// VkEvent finish_event;
// vkCmdSetEvent(cmd_buffer, finish_event,
// VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT);
}
// Flush memory.
// TODO(benvanik): subrange.
VkMappedMemoryRange dirty_range;
dirty_range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
dirty_range.pNext = nullptr;
dirty_range.memory = transient_buffer_->gpu_memory();
dirty_range.offset = 0;
dirty_range.size = transient_buffer_->capacity();
vkFlushMappedMemoryRanges(device_, 1, &dirty_range);
}
void BufferCache::InvalidateCache() {
// TODO(benvanik): caching.
}
void BufferCache::ClearCache() {
// TODO(benvanik): caching.
}
void BufferCache::Scavenge() { transient_buffer_->Scavenge(); }
} // namespace vulkan
} // namespace gpu
} // namespace xe

View File

@@ -0,0 +1,117 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2016 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_GPU_VULKAN_BUFFER_CACHE_H_
#define XENIA_GPU_VULKAN_BUFFER_CACHE_H_
#include "xenia/gpu/register_file.h"
#include "xenia/gpu/shader.h"
#include "xenia/gpu/xenos.h"
#include "xenia/ui/vulkan/circular_buffer.h"
#include "xenia/ui/vulkan/vulkan.h"
#include "xenia/ui/vulkan/vulkan_device.h"
namespace xe {
namespace gpu {
namespace vulkan {
// Efficiently manages buffers of various kinds.
// Used primarily for uploading index and vertex data from guest memory and
// transient data like shader constants.
class BufferCache {
public:
BufferCache(RegisterFile* register_file, ui::vulkan::VulkanDevice* device,
size_t capacity);
~BufferCache();
// Descriptor set containing the dynamic uniform buffer used for constant
// uploads. Used in conjunction with a dynamic offset returned by
// UploadConstantRegisters.
// The set contains two bindings:
// binding = 0: for use in vertex shaders
// binding = 1: for use in fragment shaders
VkDescriptorSet constant_descriptor_set() const {
return transient_descriptor_set_;
}
VkDescriptorSetLayout constant_descriptor_set_layout() const {
return descriptor_set_layout_;
}
// Uploads the constants specified in the register maps to the transient
// uniform storage buffer.
// The registers are tightly packed in order as [floats, ints, bools].
// Returns an offset that can be used with the transient_descriptor_set or
// VK_WHOLE_SIZE if the constants could not be uploaded (OOM).
// The returned offsets may alias.
std::pair<VkDeviceSize, VkDeviceSize> UploadConstantRegisters(
const Shader::ConstantRegisterMap& vertex_constant_register_map,
const Shader::ConstantRegisterMap& pixel_constant_register_map,
std::shared_ptr<ui::vulkan::Fence> fence);
// Uploads index buffer data from guest memory, possibly eliding with
// recently uploaded data or cached copies.
// Returns a buffer and offset that can be used with vkCmdBindIndexBuffer.
// Size will be VK_WHOLE_SIZE if the data could not be uploaded (OOM).
std::pair<VkBuffer, VkDeviceSize> UploadIndexBuffer(
const void* source_ptr, size_t source_length, IndexFormat format,
std::shared_ptr<ui::vulkan::Fence> fence);
// Uploads vertex buffer data from guest memory, possibly eliding with
// recently uploaded data or cached copies.
// Returns a buffer and offset that can be used with vkCmdBindVertexBuffers.
// Size will be VK_WHOLE_SIZE if the data could not be uploaded (OOM).
std::pair<VkBuffer, VkDeviceSize> UploadVertexBuffer(
const void* source_ptr, size_t source_length, Endian endian,
std::shared_ptr<ui::vulkan::Fence> fence);
// Flushes all pending data to the GPU.
// Until this is called the GPU is not guaranteed to see any data.
// The given command buffer will be used to queue up events so that the
// cache can determine when data has been consumed.
void Flush(VkCommandBuffer command_buffer);
// Marks the cache as potentially invalid.
// This is not as strong as ClearCache and is a hint that any and all data
// should be verified before being reused.
void InvalidateCache();
// Clears all cached content and prevents future elision with pending data.
void ClearCache();
// Wipes all data no longer needed.
void Scavenge();
private:
// Allocates a block of memory in the transient buffer.
// When memory is not available fences are checked and space is reclaimed.
// Returns VK_WHOLE_SIZE if requested amount of memory is not available.
VkDeviceSize AllocateTransientData(VkDeviceSize length,
std::shared_ptr<ui::vulkan::Fence> fence);
// Tries to allocate a block of memory in the transient buffer.
// Returns VK_WHOLE_SIZE if requested amount of memory is not available.
VkDeviceSize TryAllocateTransientData(
VkDeviceSize length, std::shared_ptr<ui::vulkan::Fence> fence);
RegisterFile* register_file_ = nullptr;
VkDevice device_ = nullptr;
// Staging ringbuffer we cycle through fast. Used for data we don't
// plan on keeping past the current frame.
std::unique_ptr<ui::vulkan::CircularBuffer> transient_buffer_ = nullptr;
VkDescriptorPool descriptor_pool_ = nullptr;
VkDescriptorSetLayout descriptor_set_layout_ = nullptr;
VkDescriptorSet transient_descriptor_set_ = nullptr;
};
} // namespace vulkan
} // namespace gpu
} // namespace xe
#endif // XENIA_GPU_VULKAN_BUFFER_CACHE_H_

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,288 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2016 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_GPU_VULKAN_PIPELINE_CACHE_H_
#define XENIA_GPU_VULKAN_PIPELINE_CACHE_H_
#include <unordered_map>
#include "third_party/xxhash/xxhash.h"
#include "xenia/gpu/register_file.h"
#include "xenia/gpu/spirv_shader_translator.h"
#include "xenia/gpu/vulkan/render_cache.h"
#include "xenia/gpu/vulkan/vulkan_shader.h"
#include "xenia/gpu/xenos.h"
#include "xenia/ui/spirv/spirv_disassembler.h"
#include "xenia/ui/vulkan/vulkan.h"
#include "xenia/ui/vulkan/vulkan_device.h"
namespace xe {
namespace gpu {
namespace vulkan {
// Configures and caches pipelines based on render state.
// This is responsible for properly setting all state required for a draw
// including shaders, various blend/etc options, and input configuration.
class PipelineCache {
public:
enum class UpdateStatus {
kCompatible,
kMismatch,
kError,
};
PipelineCache(RegisterFile* register_file, ui::vulkan::VulkanDevice* device,
VkDescriptorSetLayout uniform_descriptor_set_layout,
VkDescriptorSetLayout texture_descriptor_set_layout);
~PipelineCache();
// Loads a shader from the cache, possibly translating it.
VulkanShader* LoadShader(ShaderType shader_type, uint32_t guest_address,
const uint32_t* host_address, uint32_t dword_count);
// Configures a pipeline using the current render state and the given render
// pass. If a previously available pipeline is available it will be used,
// otherwise a new one may be created. Any state that can be set dynamically
// in the command buffer is issued at this time.
// Returns whether the pipeline could be successfully created.
UpdateStatus ConfigurePipeline(VkCommandBuffer command_buffer,
const RenderState* render_state,
VulkanShader* vertex_shader,
VulkanShader* pixel_shader,
PrimitiveType primitive_type,
VkPipeline* pipeline_out);
// Sets required dynamic state on the command buffer.
// Only state that has changed since the last call will be set unless
// full_update is true.
bool SetDynamicState(VkCommandBuffer command_buffer, bool full_update);
// Pipeline layout shared by all pipelines.
VkPipelineLayout pipeline_layout() const { return pipeline_layout_; }
// Clears all cached content.
void ClearCache();
private:
// Creates or retrieves an existing pipeline for the currently configured
// state.
VkPipeline GetPipeline(const RenderState* render_state, uint64_t hash_key);
bool TranslateShader(VulkanShader* shader, xenos::xe_gpu_program_cntl_t cntl);
void DumpShaderDisasmNV(const VkGraphicsPipelineCreateInfo& info);
// Gets a geometry shader used to emulate the given primitive type.
// Returns nullptr if the primitive doesn't need to be emulated.
VkShaderModule GetGeometryShader(PrimitiveType primitive_type,
bool is_line_mode);
RegisterFile* register_file_ = nullptr;
VkDevice device_ = nullptr;
// Reusable shader translator.
SpirvShaderTranslator shader_translator_;
// Disassembler used to get the SPIRV disasm. Only used in debug.
xe::ui::spirv::SpirvDisassembler disassembler_;
// All loaded shaders mapped by their guest hash key.
std::unordered_map<uint64_t, VulkanShader*> shader_map_;
// Vulkan pipeline cache, which in theory helps us out.
// This can be serialized to disk and reused, if we want.
VkPipelineCache pipeline_cache_ = nullptr;
// Layout used for all pipelines describing our uniforms, textures, and push
// constants.
VkPipelineLayout pipeline_layout_ = nullptr;
// Shared geometry shaders.
struct {
VkShaderModule line_quad_list;
VkShaderModule point_list;
VkShaderModule quad_list;
VkShaderModule rect_list;
} geometry_shaders_;
// Hash state used to incrementally produce pipeline hashes during update.
// By the time the full update pass has run the hash will represent the
// current state in a way that can uniquely identify the produced VkPipeline.
XXH64_state_t hash_state_;
// All previously generated pipelines mapped by hash.
std::unordered_map<uint64_t, VkPipeline> cached_pipelines_;
// Previously used pipeline. This matches our current state settings
// and allows us to quickly(ish) reuse the pipeline if no registers have
// changed.
VkPipeline current_pipeline_ = nullptr;
private:
UpdateStatus UpdateState(VulkanShader* vertex_shader,
VulkanShader* pixel_shader,
PrimitiveType primitive_type);
UpdateStatus UpdateShaderStages(VulkanShader* vertex_shader,
VulkanShader* pixel_shader,
PrimitiveType primitive_type);
UpdateStatus UpdateVertexInputState(VulkanShader* vertex_shader);
UpdateStatus UpdateInputAssemblyState(PrimitiveType primitive_type);
UpdateStatus UpdateViewportState();
UpdateStatus UpdateRasterizationState(PrimitiveType primitive_type);
UpdateStatus UpdateMultisampleState();
UpdateStatus UpdateDepthStencilState();
UpdateStatus UpdateColorBlendState();
bool SetShadowRegister(uint32_t* dest, uint32_t register_name);
bool SetShadowRegister(float* dest, uint32_t register_name);
struct UpdateRenderTargetsRegisters {
uint32_t rb_modecontrol;
uint32_t rb_surface_info;
uint32_t rb_color_info;
uint32_t rb_color1_info;
uint32_t rb_color2_info;
uint32_t rb_color3_info;
uint32_t rb_color_mask;
uint32_t rb_depthcontrol;
uint32_t rb_stencilrefmask;
uint32_t rb_depth_info;
UpdateRenderTargetsRegisters() { Reset(); }
void Reset() { std::memset(this, 0, sizeof(*this)); }
} update_render_targets_regs_;
struct UpdateShaderStagesRegisters {
PrimitiveType primitive_type;
uint32_t pa_su_sc_mode_cntl;
uint32_t sq_program_cntl;
VulkanShader* vertex_shader;
VulkanShader* pixel_shader;
UpdateShaderStagesRegisters() { Reset(); }
void Reset() { std::memset(this, 0, sizeof(*this)); }
} update_shader_stages_regs_;
VkPipelineShaderStageCreateInfo update_shader_stages_info_[3];
uint32_t update_shader_stages_stage_count_ = 0;
struct UpdateVertexInputStateRegisters {
VulkanShader* vertex_shader;
UpdateVertexInputStateRegisters() { Reset(); }
void Reset() { std::memset(this, 0, sizeof(*this)); }
} update_vertex_input_state_regs_;
VkPipelineVertexInputStateCreateInfo update_vertex_input_state_info_;
VkVertexInputBindingDescription update_vertex_input_state_binding_descrs_[64];
VkVertexInputAttributeDescription
update_vertex_input_state_attrib_descrs_[64];
struct UpdateInputAssemblyStateRegisters {
PrimitiveType primitive_type;
uint32_t pa_su_sc_mode_cntl;
uint32_t multi_prim_ib_reset_index;
UpdateInputAssemblyStateRegisters() { Reset(); }
void Reset() { std::memset(this, 0, sizeof(*this)); }
} update_input_assembly_state_regs_;
VkPipelineInputAssemblyStateCreateInfo update_input_assembly_state_info_;
struct UpdateViewportStateRegisters {
// uint32_t pa_cl_clip_cntl;
uint32_t rb_surface_info;
uint32_t pa_cl_vte_cntl;
uint32_t pa_su_sc_mode_cntl;
uint32_t pa_sc_window_offset;
uint32_t pa_sc_window_scissor_tl;
uint32_t pa_sc_window_scissor_br;
float pa_cl_vport_xoffset;
float pa_cl_vport_yoffset;
float pa_cl_vport_zoffset;
float pa_cl_vport_xscale;
float pa_cl_vport_yscale;
float pa_cl_vport_zscale;
UpdateViewportStateRegisters() { Reset(); }
void Reset() { std::memset(this, 0, sizeof(*this)); }
} update_viewport_state_regs_;
VkPipelineViewportStateCreateInfo update_viewport_state_info_;
struct UpdateRasterizationStateRegisters {
PrimitiveType primitive_type;
uint32_t pa_su_sc_mode_cntl;
uint32_t pa_sc_screen_scissor_tl;
uint32_t pa_sc_screen_scissor_br;
uint32_t pa_sc_viz_query;
uint32_t multi_prim_ib_reset_index;
UpdateRasterizationStateRegisters() { Reset(); }
void Reset() { std::memset(this, 0, sizeof(*this)); }
} update_rasterization_state_regs_;
VkPipelineRasterizationStateCreateInfo update_rasterization_state_info_;
struct UpdateMultisampleStateeRegisters {
uint32_t pa_sc_aa_config;
uint32_t pa_su_sc_mode_cntl;
uint32_t rb_surface_info;
UpdateMultisampleStateeRegisters() { Reset(); }
void Reset() { std::memset(this, 0, sizeof(*this)); }
} update_multisample_state_regs_;
VkPipelineMultisampleStateCreateInfo update_multisample_state_info_;
struct UpdateDepthStencilStateRegisters {
uint32_t rb_depthcontrol;
uint32_t rb_stencilrefmask;
UpdateDepthStencilStateRegisters() { Reset(); }
void Reset() { std::memset(this, 0, sizeof(*this)); }
} update_depth_stencil_state_regs_;
VkPipelineDepthStencilStateCreateInfo update_depth_stencil_state_info_;
struct UpdateColorBlendStateRegisters {
uint32_t rb_colorcontrol;
uint32_t rb_color_mask;
uint32_t rb_blendcontrol[4];
uint32_t rb_modecontrol;
UpdateColorBlendStateRegisters() { Reset(); }
void Reset() { std::memset(this, 0, sizeof(*this)); }
} update_color_blend_state_regs_;
VkPipelineColorBlendStateCreateInfo update_color_blend_state_info_;
VkPipelineColorBlendAttachmentState update_color_blend_attachment_states_[4];
struct SetDynamicStateRegisters {
uint32_t pa_sc_window_offset;
uint32_t pa_su_sc_mode_cntl;
uint32_t pa_sc_window_scissor_tl;
uint32_t pa_sc_window_scissor_br;
uint32_t rb_surface_info;
uint32_t pa_cl_vte_cntl;
float pa_cl_vport_xoffset;
float pa_cl_vport_yoffset;
float pa_cl_vport_zoffset;
float pa_cl_vport_xscale;
float pa_cl_vport_yscale;
float pa_cl_vport_zscale;
float rb_blend_rgba[4];
uint32_t sq_program_cntl;
uint32_t sq_context_misc;
uint32_t rb_colorcontrol;
float rb_alpha_ref;
SetDynamicStateRegisters() { Reset(); }
void Reset() { std::memset(this, 0, sizeof(*this)); }
} set_dynamic_state_registers_;
};
} // namespace vulkan
} // namespace gpu
} // namespace xe
#endif // XENIA_GPU_VULKAN_PIPELINE_CACHE_H_

View File

@@ -0,0 +1,128 @@
project_root = "../../../.."
include(project_root.."/tools/build")
group("src")
project("xenia-gpu-vulkan")
uuid("717590b4-f579-4162-8f23-0624e87d6cca")
kind("StaticLib")
language("C++")
links({
"vulkan-loader",
"xenia-base",
"xenia-gpu",
"xenia-ui",
"xenia-ui-spirv",
"xenia-ui-vulkan",
"xxhash",
})
defines({
})
includedirs({
project_root.."/third_party/gflags/src",
})
local_platform_files()
files({
"shaders/bin/*.h",
})
-- TODO(benvanik): kill this and move to the debugger UI.
group("src")
project("xenia-gpu-vulkan-trace-viewer")
uuid("86a1dddc-a26a-4885-8c55-cf745225d93e")
kind("WindowedApp")
language("C++")
links({
"gflags",
"imgui",
"vulkan-loader",
"xenia-apu",
"xenia-apu-nop",
"xenia-apu-xaudio2",
"xenia-base",
"xenia-core",
"xenia-cpu",
"xenia-cpu-backend-x64",
"xenia-gpu",
"xenia-gpu-vulkan",
"xenia-hid-nop",
"xenia-hid-winkey",
"xenia-hid-xinput",
"xenia-kernel",
"xenia-ui",
"xenia-ui-spirv",
"xenia-ui-vulkan",
"xenia-vfs",
})
flags({
"WinMain", -- Use WinMain instead of main.
})
defines({
})
includedirs({
project_root.."/third_party/gflags/src",
})
files({
"vulkan_trace_viewer_main.cc",
"../../base/main_"..platform_suffix..".cc",
})
filter("platforms:Windows")
-- Only create the .user file if it doesn't already exist.
local user_file = project_root.."/build/xenia-gpu-vulkan-trace-viewer.vcxproj.user"
if not os.isfile(user_file) then
debugdir(project_root)
debugargs({
"--flagfile=scratch/flags.txt",
"2>&1",
"1>scratch/stdout-trace-viewer.txt",
})
end
group("src")
project("xenia-gpu-vulkan-trace-dump")
uuid("0dd0dd1c-b321-494d-ab9a-6c062f0c65cc")
kind("ConsoleApp")
language("C++")
links({
"gflags",
"imgui",
"vulkan-loader",
"xenia-apu",
"xenia-apu-nop",
"xenia-apu-xaudio2",
"xenia-base",
"xenia-core",
"xenia-cpu",
"xenia-cpu-backend-x64",
"xenia-gpu",
"xenia-gpu-vulkan",
"xenia-hid-nop",
"xenia-hid-winkey",
"xenia-hid-xinput",
"xenia-kernel",
"xenia-ui",
"xenia-ui-spirv",
"xenia-ui-vulkan",
"xenia-vfs",
})
defines({
})
includedirs({
project_root.."/third_party/gflags/src",
})
files({
"vulkan_trace_dump_main.cc",
"../../base/main_"..platform_suffix..".cc",
})
filter("platforms:Windows")
-- Only create the .user file if it doesn't already exist.
local user_file = project_root.."/build/xenia-gpu-vulkan-trace-dump.vcxproj.user"
if not os.isfile(user_file) then
debugdir(project_root)
debugargs({
"--flagfile=scratch/flags.txt",
"2>&1",
"1>scratch/stdout-trace-dump.txt",
})
end

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,383 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2016 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_GPU_VULKAN_RENDER_CACHE_H_
#define XENIA_GPU_VULKAN_RENDER_CACHE_H_
#include "xenia/gpu/register_file.h"
#include "xenia/gpu/shader.h"
#include "xenia/gpu/texture_info.h"
#include "xenia/gpu/vulkan/vulkan_shader.h"
#include "xenia/gpu/xenos.h"
#include "xenia/ui/vulkan/vulkan.h"
#include "xenia/ui/vulkan/vulkan_device.h"
namespace xe {
namespace gpu {
namespace vulkan {
// TODO(benvanik): make public API?
class CachedTileView;
class CachedFramebuffer;
class CachedRenderPass;
// Uniquely identifies EDRAM tiles.
struct TileViewKey {
// Offset into EDRAM in 5120b tiles.
uint16_t tile_offset;
// Tile width of the view in base 80x16 tiles.
uint16_t tile_width;
// Tile height of the view in base 80x16 tiles.
uint16_t tile_height;
// 1 if format is ColorRenderTargetFormat, else DepthRenderTargetFormat.
uint16_t color_or_depth : 1;
// Surface MSAA samples
uint16_t msaa_samples : 2;
// Either ColorRenderTargetFormat or DepthRenderTargetFormat.
uint16_t edram_format : 13;
};
static_assert(sizeof(TileViewKey) == 8, "Key must be tightly packed");
// Cached view representing EDRAM memory.
// TODO(benvanik): reuse VkImage's with multiple VkViews for compatible
// formats?
class CachedTileView {
public:
// Key identifying the view in the cache.
TileViewKey key;
// Image
VkImage image = nullptr;
// Simple view on the image matching the format.
VkImageView image_view = nullptr;
// Memory buffer
VkDeviceMemory memory = nullptr;
// Image sample count
VkSampleCountFlagBits sample_count = VK_SAMPLE_COUNT_1_BIT;
CachedTileView(ui::vulkan::VulkanDevice* device,
VkCommandBuffer command_buffer, VkDeviceMemory edram_memory,
TileViewKey view_key);
~CachedTileView();
bool IsEqual(const TileViewKey& other_key) const {
auto a = reinterpret_cast<const uint64_t*>(&key);
auto b = reinterpret_cast<const uint64_t*>(&other_key);
return *a == *b;
}
bool operator<(const CachedTileView& other) const {
return key.tile_offset < other.key.tile_offset;
}
private:
VkDevice device_ = nullptr;
};
// Parsed render configuration from the current render state.
struct RenderConfiguration {
// Render mode (color+depth, depth-only, etc).
xenos::ModeControl mode_control;
// Target surface pitch multiplied by MSAA, in pixels.
uint32_t surface_pitch_px;
// ESTIMATED target surface height multiplied by MSAA, in pixels.
uint32_t surface_height_px;
// Surface MSAA setting.
MsaaSamples surface_msaa;
// Color attachments for the 4 render targets.
struct {
bool used;
uint32_t edram_base;
ColorRenderTargetFormat format;
} color[4];
// Depth/stencil attachment.
struct {
bool used;
uint32_t edram_base;
DepthRenderTargetFormat format;
} depth_stencil;
};
// Current render state based on the register-specified configuration.
struct RenderState {
// Parsed configuration.
RenderConfiguration config;
// Render pass (to be used with pipelines/etc).
CachedRenderPass* render_pass = nullptr;
VkRenderPass render_pass_handle = nullptr;
// Target framebuffer bound to the render pass.
CachedFramebuffer* framebuffer = nullptr;
VkFramebuffer framebuffer_handle = nullptr;
bool color_attachment_written[4] = {false};
bool depth_attachment_written = false;
};
// Manages the virtualized EDRAM and the render target cache.
//
// On the 360 the render target is an opaque block of memory in EDRAM that's
// only accessible via resolves. We use this to our advantage to simulate
// something like it as best we can by having a shared backing memory with
// a multitude of views for each tile location in EDRAM.
//
// This allows us to have the same base address write to the same memory
// regardless of framebuffer format. Resolving then uses whatever format the
// resolve requests straight from the backing memory.
//
// EDRAM is a beast and we only approximate it as best we can. Basically,
// the 10MiB of EDRAM is composed of 2048 5120b tiles. Each tile is 80x16px.
// +-----+-----+-----+---
// |tile0|tile1|tile2|... 2048 times
// +-----+-----+-----+---
// Operations dealing with EDRAM deal in tile offsets, so base 0x100 is tile
// offset 256, 256*5120=1310720b into the buffer. All rendering operations are
// aligned to tiles so trying to draw at 256px wide will have a real width of
// 320px by rounding up to the next tile.
//
// MSAA and other settings will modify the exact pixel sizes, like 4X makes
// each tile effectively 40x8px / 2X makes each tile 80x8px, but they are still
// all 5120b. As we try to emulate this we adjust our viewport when rendering to
// stretch pixels as needed.
//
// It appears that games also take advantage of MSAA stretching tiles when doing
// clears. Games will clear a view with 1/2X pitch/height and 4X MSAA and then
// later draw to that view with 1X pitch/height and 1X MSAA.
//
// The good news is that games cannot read EDRAM directly but must use a copy
// operation to get the data out. That gives us a chance to do whatever we
// need to (re-tile, etc) only when requested.
//
// To approximate the tiled EDRAM layout we use a single large chunk of memory.
// From this memory we create many VkImages (and VkImageViews) of various
// formats and dimensions as requested by the game. These are used as
// attachments during rendering and as sources during copies. They are also
// heavily aliased - lots of images will reference the same locations in the
// underlying EDRAM buffer. The only requirement is that there are no hazards
// with specific tiles (reading/writing the same tile through different images)
// and otherwise it should be ok *fingers crossed*.
//
// One complication is the copy/resolve process itself: we need to give back
// the data asked for in the format desired and where it goes is arbitrary
// (any address in physical memory). If the game is good we get resolves of
// EDRAM into fixed base addresses with scissored regions. If the game is bad
// we are broken.
//
// Resolves from EDRAM result in tiled textures - that's texture tiles, not
// EDRAM tiles. If we wanted to ensure byte-for-byte correctness we'd need to
// then tile the images as we wrote them out. For now, we just attempt to
// get the (X, Y) in linear space and do that. This really comes into play
// when multiple resolves write to the same texture or memory aliased by
// multiple textures - which is common due to predicated tiling. The examples
// below demonstrate what this looks like, but the important thing is that
// we are aware of partial textures and overlapping regions.
//
// TODO(benvanik): what, if any, barriers do we need? any transitions?
//
// Example with multiple render targets:
// Two color targets of 256x256px tightly packed in EDRAM:
// color target 0: base 0x0, pitch 320, scissor 0,0, 256x256
// starts at tile 0, buffer offset 0
// contains 64 tiles (320/80)*(256/16)
// color target 1: base 0x40, pitch 320, scissor 256,0, 256x256
// starts at tile 64 (after color target 0), buffer offset 327680b
// contains 64 tiles
// In EDRAM each set of 64 tiles is contiguous:
// +------+------+ +------+------+------+
// |ct0.0 |ct0.1 |...|ct0.63|ct1.0 |ct1.1 |...
// +------+------+ +------+------+------+
// To render into these, we setup two VkImages:
// image 0: bound to buffer offset 0, 320x256x4=327680b
// image 1: bound to buffer offset 327680b, 320x256x4=327680b
// So when we render to them:
// +------+-+ scissored to 256x256, actually 320x256
// | . | | <- . appears at some untiled offset in the buffer, but
// | | | consistent if aliased with the same format
// +------+-+
// In theory, this gives us proper aliasing in most cases.
//
// Example with horizontal predicated tiling:
// Trying to render 1024x576 @4X MSAA, splitting into two regions
// horizontally:
// +----------+
// | 1024x288 |
// +----------+
// | 1024x288 |
// +----------+
// EDRAM configured for 1056x288px with tile size 2112x567px (4X MSAA):
// color target 0: base 0x0, pitch 1080, 26x36 tiles
// First render (top):
// window offset 0,0
// scissor 0,0, 1024x288
// First resolve (top):
// RB_COPY_DEST_BASE 0x1F45D000
// RB_COPY_DEST_PITCH pitch=1024, height=576
// vertices: 0,0, 1024,0, 1024,288
// Second render (bottom):
// window offset 0,-288
// scissor 0,288, 1024x288
// Second resolve (bottom):
// RB_COPY_DEST_BASE 0x1F57D000 (+1179648b)
// RB_COPY_DEST_PITCH pitch=1024, height=576
// (exactly 1024x288*4b after first resolve)
// vertices: 0,288, 1024,288, 1024,576
// Resolving here is easy as the textures are contiguous in memory. We can
// snoop in the first resolve with the dest height to know the total size,
// and in the second resolve see that it overlaps and place it in the
// existing target.
//
// Example with vertical predicated tiling:
// Trying to render 1280x720 @2X MSAA, splitting into two regions
// vertically:
// +-----+-----+
// | 640 | 640 |
// | x | x |
// | 720 | 720 |
// +-----+-----+
// EDRAM configured for 640x736px with tile size 640x1472px (2X MSAA):
// color target 0: base 0x0, pitch 640, 8x92 tiles
// First render (left):
// window offset 0,0
// scissor 0,0, 640x720
// First resolve (left):
// RB_COPY_DEST_BASE 0x1BC6D000
// RB_COPY_DEST_PITCH pitch=1280, height=720
// vertices: 0,0, 640,0, 640,720
// Second render (right):
// window offset -640,0
// scissor 640,0, 640x720
// Second resolve (right):
// RB_COPY_DEST_BASE 0x1BC81000 (+81920b)
// RB_COPY_DEST_PITCH pitch=1280, height=720
// vertices: 640,0, 1280,0, 1280,720
// Resolving here is much more difficult as resolves are tiled and the right
// half of the texture is 81920b away:
// 81920/4bpp=20480px, /32 (texture tile size)=640px
// We know the texture size with the first resolve and with the second we
// must check for overlap then compute the offset (in both X and Y).
class RenderCache {
public:
RenderCache(RegisterFile* register_file, ui::vulkan::VulkanDevice* device);
~RenderCache();
// Call this to determine if you should start a new render pass or continue
// with an already open pass.
bool dirty() const;
// Begins a render pass targeting the state-specified framebuffer formats.
// The command buffer will be transitioned into the render pass phase.
const RenderState* BeginRenderPass(VkCommandBuffer command_buffer,
VulkanShader* vertex_shader,
VulkanShader* pixel_shader);
// Ends the current render pass.
// The command buffer will be transitioned out of the render pass phase.
void EndRenderPass();
// Clears all cached content.
void ClearCache();
// Queues commands to copy EDRAM contents into an image.
// The command buffer must not be inside of a render pass when calling this.
void RawCopyToImage(VkCommandBuffer command_buffer, uint32_t edram_base,
VkImage image, VkImageLayout image_layout,
bool color_or_depth, VkOffset3D offset,
VkExtent3D extents);
// Queues commands to blit EDRAM contents into an image.
// The command buffer must not be inside of a render pass when calling this.
void BlitToImage(VkCommandBuffer command_buffer, uint32_t edram_base,
uint32_t pitch, uint32_t height, MsaaSamples num_samples,
VkImage image, VkImageLayout image_layout,
bool color_or_depth, uint32_t format, VkFilter filter,
VkOffset3D offset, VkExtent3D extents);
// Queues commands to clear EDRAM contents with a solid color.
// The command buffer must not be inside of a render pass when calling this.
void ClearEDRAMColor(VkCommandBuffer command_buffer, uint32_t edram_base,
ColorRenderTargetFormat format, uint32_t pitch,
uint32_t height, MsaaSamples num_samples, float* color);
// Queues commands to clear EDRAM contents with depth/stencil values.
// The command buffer must not be inside of a render pass when calling this.
void ClearEDRAMDepthStencil(VkCommandBuffer command_buffer,
uint32_t edram_base,
DepthRenderTargetFormat format, uint32_t pitch,
uint32_t height, MsaaSamples num_samples,
float depth, uint32_t stencil);
// Queues commands to fill EDRAM contents with a constant value.
// The command buffer must not be inside of a render pass when calling this.
void FillEDRAM(VkCommandBuffer command_buffer, uint32_t value);
private:
// Parses the current state into a configuration object.
bool ParseConfiguration(RenderConfiguration* config);
// Finds a tile view. Returns nullptr if none found matching the key.
CachedTileView* FindTileView(const TileViewKey& view_key) const;
// Gets or creates a tile view with the given parameters.
CachedTileView* FindOrCreateTileView(VkCommandBuffer command_buffer,
const TileViewKey& view_key);
void UpdateTileView(VkCommandBuffer command_buffer, CachedTileView* view,
bool load, bool insert_barrier = true);
// Gets or creates a render pass and frame buffer for the given configuration.
// This attempts to reuse as much as possible across render passes and
// framebuffers.
bool ConfigureRenderPass(VkCommandBuffer command_buffer,
RenderConfiguration* config,
CachedRenderPass** out_render_pass,
CachedFramebuffer** out_framebuffer);
RegisterFile* register_file_ = nullptr;
ui::vulkan::VulkanDevice* device_ = nullptr;
// Entire 10MiB of EDRAM.
VkDeviceMemory edram_memory_ = nullptr;
// Buffer overlayed 1:1 with edram_memory_ to allow raw access.
VkBuffer edram_buffer_ = nullptr;
// Cache of VkImage and VkImageView's for all of our EDRAM tilings.
// TODO(benvanik): non-linear lookup? Should only be a small number of these.
std::vector<CachedTileView*> cached_tile_views_;
// Cache of render passes based on formats.
std::vector<CachedRenderPass*> cached_render_passes_;
// Shadows of the registers that impact the render pass we choose.
// If the registers don't change between passes we can quickly reuse the
// previous one.
struct ShadowRegisters {
uint32_t rb_modecontrol;
uint32_t rb_surface_info;
uint32_t rb_color_info;
uint32_t rb_color1_info;
uint32_t rb_color2_info;
uint32_t rb_color3_info;
uint32_t rb_depth_info;
uint32_t pa_sc_window_scissor_tl;
uint32_t pa_sc_window_scissor_br;
ShadowRegisters() { Reset(); }
void Reset() { std::memset(this, 0, sizeof(*this)); }
} shadow_registers_;
bool SetShadowRegister(uint32_t* dest, uint32_t register_name);
// Configuration used for the current/previous Begin/End, representing the
// current shadow register state.
RenderState current_state_;
// Only valid during a BeginRenderPass/EndRenderPass block.
VkCommandBuffer current_command_buffer_ = nullptr;
};
} // namespace vulkan
} // namespace gpu
} // namespace xe
#endif // XENIA_GPU_VULKAN_RENDER_CACHE_H_

View File

@@ -0,0 +1,187 @@
// generated from `xb genspirv`
// source: line_quad_list.geom
const uint8_t line_quad_list_geom[] = {
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x08, 0x00,
0x4C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00,
0x02, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x18, 0x00, 0x00, 0x00,
0x11, 0x00, 0x02, 0x00, 0x20, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x06, 0x00,
0x01, 0x00, 0x00, 0x00, 0x47, 0x4C, 0x53, 0x4C, 0x2E, 0x73, 0x74, 0x64,
0x2E, 0x34, 0x35, 0x30, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x03, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x09, 0x00,
0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E,
0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
0x23, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00,
0x04, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x10, 0x00, 0x04, 0x00,
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x10, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,
0x10, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00,
0x05, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00,
0xC2, 0x01, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00,
0x6D, 0x61, 0x69, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00,
0x0B, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x50, 0x65, 0x72, 0x56, 0x65,
0x72, 0x74, 0x65, 0x78, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00,
0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x50,
0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x00, 0x06, 0x00, 0x07, 0x00,
0x0B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x50,
0x6F, 0x69, 0x6E, 0x74, 0x53, 0x69, 0x7A, 0x65, 0x00, 0x00, 0x00, 0x00,
0x06, 0x00, 0x07, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x67, 0x6C, 0x5F, 0x43, 0x6C, 0x69, 0x70, 0x44, 0x69, 0x73, 0x74, 0x61,
0x6E, 0x63, 0x65, 0x00, 0x05, 0x00, 0x03, 0x00, 0x0D, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x10, 0x00, 0x00, 0x00,
0x67, 0x6C, 0x5F, 0x50, 0x65, 0x72, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78,
0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x10, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x50, 0x6F, 0x73, 0x69, 0x74,
0x69, 0x6F, 0x6E, 0x00, 0x06, 0x00, 0x07, 0x00, 0x10, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x50, 0x6F, 0x69, 0x6E, 0x74,
0x53, 0x69, 0x7A, 0x65, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x07, 0x00,
0x10, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x43,
0x6C, 0x69, 0x70, 0x44, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x00,
0x05, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x69,
0x6E, 0x00, 0x00, 0x00, 0x05, 0x00, 0x07, 0x00, 0x23, 0x00, 0x00, 0x00,
0x6F, 0x75, 0x74, 0x5F, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x6F, 0x6C,
0x61, 0x74, 0x6F, 0x72, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x07, 0x00,
0x26, 0x00, 0x00, 0x00, 0x69, 0x6E, 0x5F, 0x69, 0x6E, 0x74, 0x65, 0x72,
0x70, 0x6F, 0x6C, 0x61, 0x74, 0x6F, 0x72, 0x73, 0x00, 0x00, 0x00, 0x00,
0x48, 0x00, 0x05, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00,
0x0B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x0B, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x47, 0x00, 0x03, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x48, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00,
0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x47, 0x00, 0x03, 0x00, 0x10, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x47, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x26, 0x00, 0x00, 0x00,
0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00,
0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00,
0x08, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x2B, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x05, 0x00,
0x0B, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
0x0A, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0C, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00,
0x0C, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x15, 0x00, 0x04, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x0E, 0x00, 0x00, 0x00,
0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x05, 0x00,
0x10, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
0x0A, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00,
0x11, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x04, 0x00,
0x12, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
0x20, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x12, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
0x15, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x20, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x0E, 0x00, 0x00, 0x00,
0x1A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
0x1B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
0x20, 0x00, 0x04, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x04, 0x00,
0x21, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
0x20, 0x00, 0x04, 0x00, 0x22, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x21, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x22, 0x00, 0x00, 0x00,
0x23, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x04, 0x00,
0x24, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
0x20, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x24, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00,
0x26, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
0x27, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,
0x2B, 0x00, 0x04, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x0E, 0x00, 0x00, 0x00,
0x3B, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00,
0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00,
0x41, 0x00, 0x06, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,
0x3D, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,
0x16, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x18, 0x00, 0x00, 0x00,
0x19, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,
0x3E, 0x00, 0x03, 0x00, 0x19, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,
0x41, 0x00, 0x06, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00,
0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00,
0x1C, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x1E, 0x00, 0x00, 0x00,
0x1F, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00,
0x3E, 0x00, 0x03, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00,
0x41, 0x00, 0x05, 0x00, 0x27, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
0x26, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x21, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
0x3E, 0x00, 0x03, 0x00, 0x23, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00,
0xDA, 0x00, 0x01, 0x00, 0x41, 0x00, 0x06, 0x00, 0x15, 0x00, 0x00, 0x00,
0x2A, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00,
0x0F, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00,
0x2B, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00,
0x18, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,
0x0F, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x2C, 0x00, 0x00, 0x00,
0x2B, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x1B, 0x00, 0x00, 0x00,
0x2D, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00,
0x1A, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,
0x2E, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00,
0x1E, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,
0x1A, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x2F, 0x00, 0x00, 0x00,
0x2E, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x27, 0x00, 0x00, 0x00,
0x30, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00,
0x3D, 0x00, 0x04, 0x00, 0x21, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00,
0x30, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x23, 0x00, 0x00, 0x00,
0x31, 0x00, 0x00, 0x00, 0xDA, 0x00, 0x01, 0x00, 0x41, 0x00, 0x06, 0x00,
0x15, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
0x32, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x07, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00,
0x41, 0x00, 0x05, 0x00, 0x18, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00,
0x0D, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00,
0x35, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00,
0x1B, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
0x32, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x06, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,
0x41, 0x00, 0x05, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
0x0D, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00,
0x38, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00,
0x27, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00,
0x32, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x21, 0x00, 0x00, 0x00,
0x3A, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00,
0x23, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0xDA, 0x00, 0x01, 0x00,
0x41, 0x00, 0x06, 0x00, 0x15, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,
0x3D, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x00, 0x00,
0x3C, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x18, 0x00, 0x00, 0x00,
0x3E, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,
0x3E, 0x00, 0x03, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x00, 0x00,
0x41, 0x00, 0x06, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00,
0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
0x3F, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x1E, 0x00, 0x00, 0x00,
0x41, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00,
0x3E, 0x00, 0x03, 0x00, 0x41, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
0x41, 0x00, 0x05, 0x00, 0x27, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00,
0x26, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x21, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00,
0x3E, 0x00, 0x03, 0x00, 0x23, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00,
0xDA, 0x00, 0x01, 0x00, 0x41, 0x00, 0x06, 0x00, 0x15, 0x00, 0x00, 0x00,
0x44, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,
0x0F, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00,
0x45, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00,
0x18, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,
0x0F, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x46, 0x00, 0x00, 0x00,
0x45, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x1B, 0x00, 0x00, 0x00,
0x47, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,
0x1A, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,
0x48, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00,
0x1E, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,
0x1A, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x49, 0x00, 0x00, 0x00,
0x48, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x27, 0x00, 0x00, 0x00,
0x4A, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,
0x3D, 0x00, 0x04, 0x00, 0x21, 0x00, 0x00, 0x00, 0x4B, 0x00, 0x00, 0x00,
0x4A, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x23, 0x00, 0x00, 0x00,
0x4B, 0x00, 0x00, 0x00, 0xDA, 0x00, 0x01, 0x00, 0xDB, 0x00, 0x01, 0x00,
0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00,
};

View File

@@ -0,0 +1,136 @@
; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 1
; Bound: 76
; Schema: 0
OpCapability Geometry
OpCapability GeometryPointSize
OpCapability ClipDistance
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Geometry %4 "main" %13 %20 %35 %38
OpExecutionMode %4 InputLinesAdjacency
OpExecutionMode %4 Invocations 1
OpExecutionMode %4 OutputLineStrip
OpExecutionMode %4 OutputVertices 5
OpSource GLSL 450
OpName %4 "main"
OpName %11 "gl_PerVertex"
OpMemberName %11 0 "gl_Position"
OpMemberName %11 1 "gl_PointSize"
OpMemberName %11 2 "gl_ClipDistance"
OpName %13 ""
OpName %16 "gl_PerVertex"
OpMemberName %16 0 "gl_Position"
OpMemberName %16 1 "gl_PointSize"
OpMemberName %16 2 "gl_ClipDistance"
OpName %20 "gl_in"
OpName %35 "out_interpolators"
OpName %38 "in_interpolators"
OpMemberDecorate %11 0 BuiltIn Position
OpMemberDecorate %11 1 BuiltIn PointSize
OpMemberDecorate %11 2 BuiltIn ClipDistance
OpDecorate %11 Block
OpMemberDecorate %16 0 BuiltIn Position
OpMemberDecorate %16 1 BuiltIn PointSize
OpMemberDecorate %16 2 BuiltIn ClipDistance
OpDecorate %16 Block
OpDecorate %35 Location 0
OpDecorate %38 Location 0
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeFloat 32
%7 = OpTypeVector %6 4
%8 = OpTypeInt 32 0
%9 = OpConstant %8 1
%10 = OpTypeArray %6 %9
%11 = OpTypeStruct %7 %6 %10
%12 = OpTypePointer Output %11
%13 = OpVariable %12 Output
%14 = OpTypeInt 32 1
%15 = OpConstant %14 0
%16 = OpTypeStruct %7 %6 %10
%17 = OpConstant %8 4
%18 = OpTypeArray %16 %17
%19 = OpTypePointer Input %18
%20 = OpVariable %19 Input
%21 = OpTypePointer Input %7
%24 = OpTypePointer Output %7
%26 = OpConstant %14 1
%27 = OpTypePointer Input %6
%30 = OpTypePointer Output %6
%32 = OpConstant %8 16
%33 = OpTypeArray %7 %32
%34 = OpTypePointer Output %33
%35 = OpVariable %34 Output
%36 = OpTypeArray %33 %17
%37 = OpTypePointer Input %36
%38 = OpVariable %37 Input
%39 = OpTypePointer Input %33
%50 = OpConstant %14 2
%59 = OpConstant %14 3
%4 = OpFunction %2 None %3
%5 = OpLabel
%22 = OpAccessChain %21 %20 %15 %15
%23 = OpLoad %7 %22
%25 = OpAccessChain %24 %13 %15
OpStore %25 %23
%28 = OpAccessChain %27 %20 %15 %26
%29 = OpLoad %6 %28
%31 = OpAccessChain %30 %13 %26
OpStore %31 %29
%40 = OpAccessChain %39 %38 %15
%41 = OpLoad %33 %40
OpStore %35 %41
OpEmitVertex
%42 = OpAccessChain %21 %20 %26 %15
%43 = OpLoad %7 %42
%44 = OpAccessChain %24 %13 %15
OpStore %44 %43
%45 = OpAccessChain %27 %20 %26 %26
%46 = OpLoad %6 %45
%47 = OpAccessChain %30 %13 %26
OpStore %47 %46
%48 = OpAccessChain %39 %38 %26
%49 = OpLoad %33 %48
OpStore %35 %49
OpEmitVertex
%51 = OpAccessChain %21 %20 %50 %15
%52 = OpLoad %7 %51
%53 = OpAccessChain %24 %13 %15
OpStore %53 %52
%54 = OpAccessChain %27 %20 %50 %26
%55 = OpLoad %6 %54
%56 = OpAccessChain %30 %13 %26
OpStore %56 %55
%57 = OpAccessChain %39 %38 %50
%58 = OpLoad %33 %57
OpStore %35 %58
OpEmitVertex
%60 = OpAccessChain %21 %20 %59 %15
%61 = OpLoad %7 %60
%62 = OpAccessChain %24 %13 %15
OpStore %62 %61
%63 = OpAccessChain %27 %20 %59 %26
%64 = OpLoad %6 %63
%65 = OpAccessChain %30 %13 %26
OpStore %65 %64
%66 = OpAccessChain %39 %38 %59
%67 = OpLoad %33 %66
OpStore %35 %67
OpEmitVertex
%68 = OpAccessChain %21 %20 %15 %15
%69 = OpLoad %7 %68
%70 = OpAccessChain %24 %13 %15
OpStore %70 %69
%71 = OpAccessChain %27 %20 %15 %26
%72 = OpLoad %6 %71
%73 = OpAccessChain %30 %13 %26
OpStore %73 %72
%74 = OpAccessChain %39 %38 %15
%75 = OpLoad %33 %74
OpStore %35 %75
OpEmitVertex
OpEndPrimitive
OpReturn
OpFunctionEnd

View File

@@ -0,0 +1,200 @@
// generated from `xb genspirv`
// source: point_list.geom
const uint8_t point_list_geom[] = {
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x08, 0x00,
0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00,
0x02, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x18, 0x00, 0x00, 0x00,
0x11, 0x00, 0x02, 0x00, 0x20, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x06, 0x00,
0x01, 0x00, 0x00, 0x00, 0x47, 0x4C, 0x53, 0x4C, 0x2E, 0x73, 0x74, 0x64,
0x2E, 0x34, 0x35, 0x30, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x03, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x09, 0x00,
0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E,
0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00,
0x4C, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00,
0x04, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x10, 0x00, 0x04, 0x00,
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x10, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00,
0x10, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00,
0xC2, 0x01, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00,
0x6D, 0x61, 0x69, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00,
0x09, 0x00, 0x00, 0x00, 0x70, 0x6F, 0x73, 0x00, 0x05, 0x00, 0x06, 0x00,
0x0D, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x50, 0x65, 0x72, 0x56, 0x65,
0x72, 0x74, 0x65, 0x78, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00,
0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x50,
0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x00, 0x06, 0x00, 0x07, 0x00,
0x0D, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x50,
0x6F, 0x69, 0x6E, 0x74, 0x53, 0x69, 0x7A, 0x65, 0x00, 0x00, 0x00, 0x00,
0x06, 0x00, 0x07, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x67, 0x6C, 0x5F, 0x43, 0x6C, 0x69, 0x70, 0x44, 0x69, 0x73, 0x74, 0x61,
0x6E, 0x63, 0x65, 0x00, 0x05, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00,
0x67, 0x6C, 0x5F, 0x69, 0x6E, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00,
0x17, 0x00, 0x00, 0x00, 0x70, 0x73, 0x69, 0x7A, 0x65, 0x00, 0x00, 0x00,
0x05, 0x00, 0x03, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00,
0x05, 0x00, 0x06, 0x00, 0x27, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x50,
0x65, 0x72, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x00, 0x00, 0x00, 0x00,
0x06, 0x00, 0x06, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x67, 0x6C, 0x5F, 0x50, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x00,
0x06, 0x00, 0x07, 0x00, 0x27, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x67, 0x6C, 0x5F, 0x50, 0x6F, 0x69, 0x6E, 0x74, 0x53, 0x69, 0x7A, 0x65,
0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x07, 0x00, 0x27, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x43, 0x6C, 0x69, 0x70, 0x44,
0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x00, 0x05, 0x00, 0x03, 0x00,
0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00,
0x38, 0x00, 0x00, 0x00, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x61, 0x62, 0x6C,
0x65, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x4A, 0x00, 0x00, 0x00,
0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x44, 0x61, 0x74, 0x61, 0x00, 0x00,
0x06, 0x00, 0x04, 0x00, 0x4A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x6F, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x4C, 0x00, 0x00, 0x00,
0x6F, 0x75, 0x74, 0x5F, 0x76, 0x74, 0x78, 0x00, 0x05, 0x00, 0x05, 0x00,
0x4D, 0x00, 0x00, 0x00, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x44, 0x61,
0x74, 0x61, 0x00, 0x00, 0x06, 0x00, 0x04, 0x00, 0x4D, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00,
0x50, 0x00, 0x00, 0x00, 0x69, 0x6E, 0x5F, 0x76, 0x74, 0x78, 0x00, 0x00,
0x48, 0x00, 0x05, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00,
0x0D, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x0D, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x47, 0x00, 0x03, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x48, 0x00, 0x05, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00,
0x27, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x27, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x47, 0x00, 0x03, 0x00, 0x27, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x48, 0x00, 0x05, 0x00, 0x4A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00,
0x4D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00,
0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00,
0x0A, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x2B, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x04, 0x00, 0x0C, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x05, 0x00,
0x0D, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
0x0C, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x04, 0x00, 0x0E, 0x00, 0x00, 0x00,
0x0D, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
0x0F, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00,
0x3B, 0x00, 0x04, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x11, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00,
0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x20, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00,
0x11, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x20, 0x00, 0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x1C, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00,
0x11, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x14, 0x00, 0x02, 0x00, 0x25, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x05, 0x00,
0x27, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
0x0C, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00,
0x28, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x17, 0x00, 0x04, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00,
0x2D, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x04, 0x00,
0x2E, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00,
0x2B, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00,
0x00, 0x00, 0x80, 0xBF, 0x2B, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,
0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3F, 0x2C, 0x00, 0x05, 0x00,
0x2A, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00,
0x30, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x05, 0x00, 0x2A, 0x00, 0x00, 0x00,
0x32, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
0x2C, 0x00, 0x05, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00,
0x2F, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x05, 0x00,
0x2A, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
0x2F, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x07, 0x00, 0x2E, 0x00, 0x00, 0x00,
0x35, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00,
0x33, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
0x37, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00,
0x20, 0x00, 0x04, 0x00, 0x39, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x2A, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x46, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00,
0x0A, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
0x1C, 0x00, 0x04, 0x00, 0x49, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x48, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x03, 0x00, 0x4A, 0x00, 0x00, 0x00,
0x49, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x4B, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x4A, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00,
0x4B, 0x00, 0x00, 0x00, 0x4C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x1E, 0x00, 0x03, 0x00, 0x4D, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00,
0x1C, 0x00, 0x04, 0x00, 0x4E, 0x00, 0x00, 0x00, 0x4D, 0x00, 0x00, 0x00,
0x0B, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x4F, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x4E, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00,
0x4F, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x20, 0x00, 0x04, 0x00, 0x51, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x4D, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0xF8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00,
0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x3B, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x1C, 0x00, 0x00, 0x00,
0x1D, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00,
0x37, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x41, 0x00, 0x06, 0x00, 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
0x3D, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00,
0x15, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x19, 0x00, 0x00, 0x00,
0x1A, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
0x18, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,
0x1B, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00,
0x17, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00,
0x1D, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00,
0x1E, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x1E, 0x00, 0x00, 0x00,
0xF6, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, 0x22, 0x00, 0x00, 0x00,
0xF8, 0x00, 0x02, 0x00, 0x22, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x11, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00,
0xB1, 0x00, 0x05, 0x00, 0x25, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00,
0x23, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x04, 0x00,
0x26, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
0xF8, 0x00, 0x02, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x07, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
0x4F, 0x00, 0x07, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00,
0x2B, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x11, 0x00, 0x00, 0x00,
0x36, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00,
0x38, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00,
0x39, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
0x36, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x2A, 0x00, 0x00, 0x00,
0x3B, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x06, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,
0x8E, 0x00, 0x05, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x00, 0x00,
0x3B, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00,
0x2A, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00,
0x3D, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00,
0x3F, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x4F, 0x00, 0x07, 0x00,
0x2A, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00,
0x3F, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00,
0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00,
0x06, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00,
0x43, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00,
0x07, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00,
0x42, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00,
0x41, 0x00, 0x05, 0x00, 0x46, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00,
0x29, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00,
0x47, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00,
0x51, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00,
0x12, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x4D, 0x00, 0x00, 0x00,
0x53, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00,
0x4C, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0xDA, 0x00, 0x01, 0x00,
0xF9, 0x00, 0x02, 0x00, 0x21, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00,
0x21, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x11, 0x00, 0x00, 0x00,
0x54, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00,
0x11, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
0x18, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x1D, 0x00, 0x00, 0x00,
0x55, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, 0x1E, 0x00, 0x00, 0x00,
0xF8, 0x00, 0x02, 0x00, 0x20, 0x00, 0x00, 0x00, 0xDB, 0x00, 0x01, 0x00,
0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00,
};

View File

@@ -0,0 +1,148 @@
; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 1
; Bound: 86
; Schema: 0
OpCapability Geometry
OpCapability GeometryPointSize
OpCapability ClipDistance
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Geometry %4 "main" %16 %41 %76 %80
OpExecutionMode %4 InputPoints
OpExecutionMode %4 Invocations 1
OpExecutionMode %4 OutputTriangleStrip
OpExecutionMode %4 OutputVertices 4
OpSource GLSL 450
OpName %4 "main"
OpName %9 "pos"
OpName %13 "gl_PerVertex"
OpMemberName %13 0 "gl_Position"
OpMemberName %13 1 "gl_PointSize"
OpMemberName %13 2 "gl_ClipDistance"
OpName %16 "gl_in"
OpName %23 "psize"
OpName %29 "i"
OpName %39 "gl_PerVertex"
OpMemberName %39 0 "gl_Position"
OpMemberName %39 1 "gl_PointSize"
OpMemberName %39 2 "gl_ClipDistance"
OpName %41 ""
OpName %56 "indexable"
OpName %74 "VertexData"
OpMemberName %74 0 "o"
OpName %76 "out_vtx"
OpName %77 "VertexData"
OpMemberName %77 0 "o"
OpName %80 "in_vtx"
OpMemberDecorate %13 0 BuiltIn Position
OpMemberDecorate %13 1 BuiltIn PointSize
OpMemberDecorate %13 2 BuiltIn ClipDistance
OpDecorate %13 Block
OpMemberDecorate %39 0 BuiltIn Position
OpMemberDecorate %39 1 BuiltIn PointSize
OpMemberDecorate %39 2 BuiltIn ClipDistance
OpDecorate %39 Block
OpMemberDecorate %74 0 Location 0
OpMemberDecorate %77 0 Location 0
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeFloat 32
%7 = OpTypeVector %6 4
%8 = OpTypePointer Function %7
%10 = OpTypeInt 32 0
%11 = OpConstant %10 1
%12 = OpTypeArray %6 %11
%13 = OpTypeStruct %7 %6 %12
%14 = OpTypeArray %13 %11
%15 = OpTypePointer Input %14
%16 = OpVariable %15 Input
%17 = OpTypeInt 32 1
%18 = OpConstant %17 0
%19 = OpTypePointer Input %7
%22 = OpTypePointer Function %6
%24 = OpConstant %17 1
%25 = OpTypePointer Input %6
%28 = OpTypePointer Function %17
%36 = OpConstant %17 4
%37 = OpTypeBool
%39 = OpTypeStruct %7 %6 %12
%40 = OpTypePointer Output %39
%41 = OpVariable %40 Output
%42 = OpTypeVector %6 2
%45 = OpConstant %10 4
%46 = OpTypeArray %42 %45
%47 = OpConstant %6 -1
%48 = OpConstant %6 1
%49 = OpConstantComposite %42 %47 %48
%50 = OpConstantComposite %42 %48 %48
%51 = OpConstantComposite %42 %47 %47
%52 = OpConstantComposite %42 %48 %47
%53 = OpConstantComposite %46 %49 %50 %51 %52
%55 = OpTypePointer Function %46
%57 = OpTypePointer Function %42
%70 = OpTypePointer Output %7
%72 = OpConstant %10 16
%73 = OpTypeArray %7 %72
%74 = OpTypeStruct %73
%75 = OpTypePointer Output %74
%76 = OpVariable %75 Output
%77 = OpTypeStruct %73
%78 = OpTypeArray %77 %11
%79 = OpTypePointer Input %78
%80 = OpVariable %79 Input
%81 = OpTypePointer Input %77
%4 = OpFunction %2 None %3
%5 = OpLabel
%9 = OpVariable %8 Function
%23 = OpVariable %22 Function
%29 = OpVariable %28 Function
%56 = OpVariable %55 Function
%20 = OpAccessChain %19 %16 %18 %18
%21 = OpLoad %7 %20
OpStore %9 %21
%26 = OpAccessChain %25 %16 %18 %24
%27 = OpLoad %6 %26
OpStore %23 %27
OpStore %29 %18
OpBranch %30
%30 = OpLabel
OpLoopMerge %32 %33 None
OpBranch %34
%34 = OpLabel
%35 = OpLoad %17 %29
%38 = OpSLessThan %37 %35 %36
OpBranchConditional %38 %31 %32
%31 = OpLabel
%43 = OpLoad %7 %9
%44 = OpVectorShuffle %42 %43 %43 0 1
%54 = OpLoad %17 %29
OpStore %56 %53
%58 = OpAccessChain %57 %56 %54
%59 = OpLoad %42 %58
%60 = OpLoad %6 %23
%61 = OpVectorTimesScalar %42 %59 %60
%62 = OpFAdd %42 %44 %61
%63 = OpLoad %7 %9
%64 = OpVectorShuffle %42 %63 %63 2 3
%65 = OpCompositeExtract %6 %62 0
%66 = OpCompositeExtract %6 %62 1
%67 = OpCompositeExtract %6 %64 0
%68 = OpCompositeExtract %6 %64 1
%69 = OpCompositeConstruct %7 %65 %66 %67 %68
%71 = OpAccessChain %70 %41 %18
OpStore %71 %69
%82 = OpAccessChain %81 %80 %18
%83 = OpLoad %77 %82
OpStore %76 %83
OpEmitVertex
OpBranch %33
%33 = OpLabel
%84 = OpLoad %17 %29
%85 = OpIAdd %17 %84 %24
OpStore %29 %85
OpBranch %30
%32 = OpLabel
OpEndPrimitive
OpReturn
OpFunctionEnd

View File

@@ -0,0 +1,165 @@
// generated from `xb genspirv`
// source: quad_list.geom
const uint8_t quad_list_geom[] = {
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x08, 0x00,
0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00,
0x02, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x18, 0x00, 0x00, 0x00,
0x11, 0x00, 0x02, 0x00, 0x20, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x06, 0x00,
0x01, 0x00, 0x00, 0x00, 0x47, 0x4C, 0x53, 0x4C, 0x2E, 0x73, 0x74, 0x64,
0x2E, 0x34, 0x35, 0x30, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x03, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x09, 0x00,
0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E,
0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00,
0x3A, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00,
0x04, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x10, 0x00, 0x04, 0x00,
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x10, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00,
0x10, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00,
0xC2, 0x01, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00,
0x6D, 0x61, 0x69, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00,
0x08, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00,
0x13, 0x00, 0x00, 0x00, 0x69, 0x6E, 0x70, 0x75, 0x74, 0x5F, 0x69, 0x6E,
0x64, 0x65, 0x78, 0x00, 0x05, 0x00, 0x05, 0x00, 0x1D, 0x00, 0x00, 0x00,
0x69, 0x6E, 0x64, 0x65, 0x78, 0x61, 0x62, 0x6C, 0x65, 0x00, 0x00, 0x00,
0x05, 0x00, 0x06, 0x00, 0x24, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x50,
0x65, 0x72, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x00, 0x00, 0x00, 0x00,
0x06, 0x00, 0x06, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x67, 0x6C, 0x5F, 0x50, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x00,
0x06, 0x00, 0x07, 0x00, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x67, 0x6C, 0x5F, 0x50, 0x6F, 0x69, 0x6E, 0x74, 0x53, 0x69, 0x7A, 0x65,
0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x07, 0x00, 0x24, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x43, 0x6C, 0x69, 0x70, 0x44,
0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x00, 0x05, 0x00, 0x03, 0x00,
0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00,
0x27, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x50, 0x65, 0x72, 0x56, 0x65,
0x72, 0x74, 0x65, 0x78, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00,
0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x50,
0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x00, 0x06, 0x00, 0x07, 0x00,
0x27, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x50,
0x6F, 0x69, 0x6E, 0x74, 0x53, 0x69, 0x7A, 0x65, 0x00, 0x00, 0x00, 0x00,
0x06, 0x00, 0x07, 0x00, 0x27, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x67, 0x6C, 0x5F, 0x43, 0x6C, 0x69, 0x70, 0x44, 0x69, 0x73, 0x74, 0x61,
0x6E, 0x63, 0x65, 0x00, 0x05, 0x00, 0x04, 0x00, 0x2A, 0x00, 0x00, 0x00,
0x67, 0x6C, 0x5F, 0x69, 0x6E, 0x00, 0x00, 0x00, 0x05, 0x00, 0x07, 0x00,
0x3A, 0x00, 0x00, 0x00, 0x6F, 0x75, 0x74, 0x5F, 0x69, 0x6E, 0x74, 0x65,
0x72, 0x70, 0x6F, 0x6C, 0x61, 0x74, 0x6F, 0x72, 0x73, 0x00, 0x00, 0x00,
0x05, 0x00, 0x07, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x69, 0x6E, 0x5F, 0x69,
0x6E, 0x74, 0x65, 0x72, 0x70, 0x6F, 0x6C, 0x61, 0x74, 0x6F, 0x72, 0x73,
0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x24, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x48, 0x00, 0x05, 0x00, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x0B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00,
0x24, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x24, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x27, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x48, 0x00, 0x05, 0x00, 0x27, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x0B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00,
0x27, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x27, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x3A, 0x00, 0x00, 0x00,
0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
0x3D, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00,
0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00,
0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x20, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,
0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00,
0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x14, 0x00, 0x02, 0x00, 0x11, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00,
0x14, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x2B, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00,
0x06, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x2B, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,
0x19, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x07, 0x00,
0x16, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
0x17, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,
0x20, 0x00, 0x04, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x16, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, 0x20, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x21, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00,
0x14, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x1C, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
0x22, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x05, 0x00, 0x24, 0x00, 0x00, 0x00,
0x21, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,
0x20, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x24, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00,
0x26, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x05, 0x00,
0x27, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
0x23, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00,
0x27, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
0x29, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
0x3B, 0x00, 0x04, 0x00, 0x29, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x2C, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
0x2F, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,
0x20, 0x00, 0x04, 0x00, 0x32, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x35, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00,
0x14, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
0x1C, 0x00, 0x04, 0x00, 0x38, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,
0x37, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x39, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00,
0x39, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x1C, 0x00, 0x04, 0x00, 0x3B, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
0x15, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x3C, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00,
0x3C, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x20, 0x00, 0x04, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x38, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0xF8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00,
0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x3B, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x1C, 0x00, 0x00, 0x00,
0x1D, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00,
0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00,
0x0A, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x0A, 0x00, 0x00, 0x00,
0xF6, 0x00, 0x04, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, 0x0E, 0x00, 0x00, 0x00,
0xF8, 0x00, 0x02, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x06, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0xB1, 0x00, 0x05, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
0x0F, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x04, 0x00,
0x12, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
0xF8, 0x00, 0x02, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x06, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0x3E, 0x00, 0x03, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00,
0x41, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00,
0x1D, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x06, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00,
0x3E, 0x00, 0x03, 0x00, 0x13, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00,
0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00,
0x13, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x2C, 0x00, 0x00, 0x00,
0x2D, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00,
0x09, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x21, 0x00, 0x00, 0x00,
0x2E, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00,
0x2F, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00,
0x09, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00,
0x2E, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,
0x31, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00,
0x32, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00,
0x31, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x20, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00,
0x41, 0x00, 0x05, 0x00, 0x35, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,
0x26, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00,
0x36, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x06, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
0x41, 0x00, 0x05, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
0x3D, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x38, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
0x3E, 0x00, 0x03, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00,
0xDA, 0x00, 0x01, 0x00, 0xF9, 0x00, 0x02, 0x00, 0x0D, 0x00, 0x00, 0x00,
0xF8, 0x00, 0x02, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x06, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0x80, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00,
0x42, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00,
0x08, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00,
0x0A, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x0C, 0x00, 0x00, 0x00,
0xDB, 0x00, 0x01, 0x00, 0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00,
};

View File

@@ -0,0 +1,125 @@
; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 1
; Bound: 68
; Schema: 0
OpCapability Geometry
OpCapability GeometryPointSize
OpCapability ClipDistance
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Geometry %4 "main" %38 %42 %58 %61
OpExecutionMode %4 InputLinesAdjacency
OpExecutionMode %4 Invocations 1
OpExecutionMode %4 OutputTriangleStrip
OpExecutionMode %4 OutputVertices 4
OpSource GLSL 450
OpName %4 "main"
OpName %8 "i"
OpName %19 "input_index"
OpName %29 "indexable"
OpName %36 "gl_PerVertex"
OpMemberName %36 0 "gl_Position"
OpMemberName %36 1 "gl_PointSize"
OpMemberName %36 2 "gl_ClipDistance"
OpName %38 ""
OpName %39 "gl_PerVertex"
OpMemberName %39 0 "gl_Position"
OpMemberName %39 1 "gl_PointSize"
OpMemberName %39 2 "gl_ClipDistance"
OpName %42 "gl_in"
OpName %58 "out_interpolators"
OpName %61 "in_interpolators"
OpMemberDecorate %36 0 BuiltIn Position
OpMemberDecorate %36 1 BuiltIn PointSize
OpMemberDecorate %36 2 BuiltIn ClipDistance
OpDecorate %36 Block
OpMemberDecorate %39 0 BuiltIn Position
OpMemberDecorate %39 1 BuiltIn PointSize
OpMemberDecorate %39 2 BuiltIn ClipDistance
OpDecorate %39 Block
OpDecorate %58 Location 0
OpDecorate %61 Location 0
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeInt 32 1
%7 = OpTypePointer Function %6
%9 = OpConstant %6 0
%16 = OpConstant %6 4
%17 = OpTypeBool
%20 = OpTypeInt 32 0
%21 = OpConstant %20 4
%22 = OpTypeArray %6 %21
%23 = OpConstant %6 1
%24 = OpConstant %6 3
%25 = OpConstant %6 2
%26 = OpConstantComposite %22 %9 %23 %24 %25
%28 = OpTypePointer Function %22
%32 = OpTypeFloat 32
%33 = OpTypeVector %32 4
%34 = OpConstant %20 1
%35 = OpTypeArray %32 %34
%36 = OpTypeStruct %33 %32 %35
%37 = OpTypePointer Output %36
%38 = OpVariable %37 Output
%39 = OpTypeStruct %33 %32 %35
%40 = OpTypeArray %39 %21
%41 = OpTypePointer Input %40
%42 = OpVariable %41 Input
%44 = OpTypePointer Input %33
%47 = OpTypePointer Output %33
%50 = OpTypePointer Input %32
%53 = OpTypePointer Output %32
%55 = OpConstant %20 16
%56 = OpTypeArray %33 %55
%57 = OpTypePointer Output %56
%58 = OpVariable %57 Output
%59 = OpTypeArray %56 %21
%60 = OpTypePointer Input %59
%61 = OpVariable %60 Input
%63 = OpTypePointer Input %56
%4 = OpFunction %2 None %3
%5 = OpLabel
%8 = OpVariable %7 Function
%19 = OpVariable %7 Function
%29 = OpVariable %28 Function
OpStore %8 %9
OpBranch %10
%10 = OpLabel
OpLoopMerge %12 %13 None
OpBranch %14
%14 = OpLabel
%15 = OpLoad %6 %8
%18 = OpSLessThan %17 %15 %16
OpBranchConditional %18 %11 %12
%11 = OpLabel
%27 = OpLoad %6 %8
OpStore %29 %26
%30 = OpAccessChain %7 %29 %27
%31 = OpLoad %6 %30
OpStore %19 %31
%43 = OpLoad %6 %19
%45 = OpAccessChain %44 %42 %43 %9
%46 = OpLoad %33 %45
%48 = OpAccessChain %47 %38 %9
OpStore %48 %46
%49 = OpLoad %6 %19
%51 = OpAccessChain %50 %42 %49 %23
%52 = OpLoad %32 %51
%54 = OpAccessChain %53 %38 %23
OpStore %54 %52
%62 = OpLoad %6 %19
%64 = OpAccessChain %63 %61 %62
%65 = OpLoad %56 %64
OpStore %58 %65
OpEmitVertex
OpBranch %13
%13 = OpLabel
%66 = OpLoad %6 %8
%67 = OpIAdd %6 %66 %23
OpStore %8 %67
OpBranch %10
%12 = OpLabel
OpEndPrimitive
OpReturn
OpFunctionEnd

View File

@@ -0,0 +1,423 @@
// generated from `xb genspirv`
// source: rect_list.geom
const uint8_t rect_list_geom[] = {
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x08, 0x00,
0xCA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00,
0x02, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x18, 0x00, 0x00, 0x00,
0x11, 0x00, 0x02, 0x00, 0x20, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x06, 0x00,
0x01, 0x00, 0x00, 0x00, 0x47, 0x4C, 0x53, 0x4C, 0x2E, 0x73, 0x74, 0x64,
0x2E, 0x34, 0x35, 0x30, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x03, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x09, 0x00,
0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E,
0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
0x30, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00,
0x04, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x10, 0x00, 0x04, 0x00,
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x10, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00,
0x10, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00,
0xC2, 0x01, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00,
0x6D, 0x61, 0x69, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00,
0x08, 0x00, 0x00, 0x00, 0x6C, 0x65, 0x66, 0x74, 0x5F, 0x61, 0x6C, 0x69,
0x67, 0x6E, 0x65, 0x64, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00,
0x0E, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x50, 0x65, 0x72, 0x56, 0x65,
0x72, 0x74, 0x65, 0x78, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00,
0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x50,
0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x00, 0x06, 0x00, 0x07, 0x00,
0x0E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x50,
0x6F, 0x69, 0x6E, 0x74, 0x53, 0x69, 0x7A, 0x65, 0x00, 0x00, 0x00, 0x00,
0x06, 0x00, 0x07, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x67, 0x6C, 0x5F, 0x43, 0x6C, 0x69, 0x70, 0x44, 0x69, 0x73, 0x74, 0x61,
0x6E, 0x63, 0x65, 0x00, 0x05, 0x00, 0x04, 0x00, 0x12, 0x00, 0x00, 0x00,
0x67, 0x6C, 0x5F, 0x69, 0x6E, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00,
0x20, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x50, 0x65, 0x72, 0x56, 0x65,
0x72, 0x74, 0x65, 0x78, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00,
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x50,
0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x00, 0x06, 0x00, 0x07, 0x00,
0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x50,
0x6F, 0x69, 0x6E, 0x74, 0x53, 0x69, 0x7A, 0x65, 0x00, 0x00, 0x00, 0x00,
0x06, 0x00, 0x07, 0x00, 0x20, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x67, 0x6C, 0x5F, 0x43, 0x6C, 0x69, 0x70, 0x44, 0x69, 0x73, 0x74, 0x61,
0x6E, 0x63, 0x65, 0x00, 0x05, 0x00, 0x03, 0x00, 0x22, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x07, 0x00, 0x30, 0x00, 0x00, 0x00,
0x6F, 0x75, 0x74, 0x5F, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x6F, 0x6C,
0x61, 0x74, 0x6F, 0x72, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x07, 0x00,
0x33, 0x00, 0x00, 0x00, 0x69, 0x6E, 0x5F, 0x69, 0x6E, 0x74, 0x65, 0x72,
0x70, 0x6F, 0x6C, 0x61, 0x74, 0x6F, 0x72, 0x73, 0x00, 0x00, 0x00, 0x00,
0x05, 0x00, 0x03, 0x00, 0x64, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00,
0x05, 0x00, 0x03, 0x00, 0xB2, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00,
0x48, 0x00, 0x05, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00,
0x0E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x0E, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x47, 0x00, 0x03, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x48, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00,
0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x47, 0x00, 0x03, 0x00, 0x20, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x47, 0x00, 0x04, 0x00, 0x30, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x33, 0x00, 0x00, 0x00,
0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00,
0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02, 0x00, 0x06, 0x00, 0x00, 0x00,
0x20, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00,
0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00,
0x0B, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x2B, 0x00, 0x04, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x04, 0x00, 0x0D, 0x00, 0x00, 0x00,
0x09, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x05, 0x00,
0x0E, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
0x0D, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x0B, 0x00, 0x00, 0x00,
0x0F, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x04, 0x00,
0x10, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,
0x20, 0x00, 0x04, 0x00, 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x11, 0x00, 0x00, 0x00,
0x12, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00,
0x13, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x2B, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x0B, 0x00, 0x00, 0x00,
0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
0x16, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
0x2B, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00,
0x0A, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,
0x20, 0x00, 0x04, 0x00, 0x21, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x21, 0x00, 0x00, 0x00,
0x22, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
0x23, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,
0x20, 0x00, 0x04, 0x00, 0x26, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x0A, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00,
0x28, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
0x2B, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
0x2B, 0x00, 0x04, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x04, 0x00, 0x2E, 0x00, 0x00, 0x00,
0x0A, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
0x2F, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00,
0x3B, 0x00, 0x04, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x04, 0x00, 0x31, 0x00, 0x00, 0x00,
0x2E, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
0x32, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00,
0x3B, 0x00, 0x04, 0x00, 0x32, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x34, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
0x63, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
0x2B, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0x6B, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0xF8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00,
0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x3B, 0x00, 0x04, 0x00, 0x63, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x63, 0x00, 0x00, 0x00,
0xB2, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x41, 0x00, 0x07, 0x00,
0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,
0x3D, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
0x17, 0x00, 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, 0x16, 0x00, 0x00, 0x00,
0x1A, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x09, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00,
0xB4, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,
0x18, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00,
0x08, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x06, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0xF7, 0x00, 0x03, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFA, 0x00, 0x04, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00,
0x7D, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x1E, 0x00, 0x00, 0x00,
0x41, 0x00, 0x06, 0x00, 0x23, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
0x3D, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,
0x24, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x26, 0x00, 0x00, 0x00,
0x27, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
0x3E, 0x00, 0x03, 0x00, 0x27, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,
0x41, 0x00, 0x06, 0x00, 0x16, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00,
0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
0x3D, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00,
0x29, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x2B, 0x00, 0x00, 0x00,
0x2C, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
0x3E, 0x00, 0x03, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00,
0x41, 0x00, 0x05, 0x00, 0x34, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00,
0x33, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x2E, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00,
0x3E, 0x00, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,
0xDA, 0x00, 0x01, 0x00, 0x41, 0x00, 0x06, 0x00, 0x23, 0x00, 0x00, 0x00,
0x37, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00,
0x38, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00,
0x26, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x39, 0x00, 0x00, 0x00,
0x38, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x16, 0x00, 0x00, 0x00,
0x3A, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
0x28, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00,
0x3B, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00,
0x2B, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
0x28, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x3C, 0x00, 0x00, 0x00,
0x3B, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x34, 0x00, 0x00, 0x00,
0x3D, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
0x3D, 0x00, 0x04, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00,
0x3D, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00,
0x3E, 0x00, 0x00, 0x00, 0xDA, 0x00, 0x01, 0x00, 0x41, 0x00, 0x06, 0x00,
0x23, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
0x19, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x0A, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00,
0x41, 0x00, 0x05, 0x00, 0x26, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00,
0x22, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00,
0x41, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00,
0x16, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
0x19, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x09, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00,
0x41, 0x00, 0x05, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00,
0x22, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00,
0x44, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00,
0x34, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00,
0x19, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x2E, 0x00, 0x00, 0x00,
0x46, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00,
0x30, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0xDA, 0x00, 0x01, 0x00,
0xDB, 0x00, 0x01, 0x00, 0x41, 0x00, 0x06, 0x00, 0x23, 0x00, 0x00, 0x00,
0x47, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00,
0x48, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00,
0x26, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x49, 0x00, 0x00, 0x00,
0x48, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x16, 0x00, 0x00, 0x00,
0x4A, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,
0x28, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00,
0x4B, 0x00, 0x00, 0x00, 0x4A, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00,
0x2B, 0x00, 0x00, 0x00, 0x4C, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
0x28, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x4C, 0x00, 0x00, 0x00,
0x4B, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x34, 0x00, 0x00, 0x00,
0x4D, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,
0x3D, 0x00, 0x04, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x4E, 0x00, 0x00, 0x00,
0x4D, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00,
0x4E, 0x00, 0x00, 0x00, 0xDA, 0x00, 0x01, 0x00, 0x41, 0x00, 0x06, 0x00,
0x23, 0x00, 0x00, 0x00, 0x4F, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
0x28, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x0A, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x4F, 0x00, 0x00, 0x00,
0x41, 0x00, 0x05, 0x00, 0x26, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00,
0x22, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00,
0x51, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00,
0x16, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
0x28, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x09, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00,
0x41, 0x00, 0x05, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
0x22, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00,
0x54, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00,
0x34, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00,
0x28, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x2E, 0x00, 0x00, 0x00,
0x56, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00,
0x30, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0xDA, 0x00, 0x01, 0x00,
0x41, 0x00, 0x06, 0x00, 0x23, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00,
0x12, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
0x3D, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00,
0x57, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x23, 0x00, 0x00, 0x00,
0x59, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00,
0x5A, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00,
0x0A, 0x00, 0x00, 0x00, 0x5B, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00,
0x5A, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x23, 0x00, 0x00, 0x00,
0x5C, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00,
0x5D, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00,
0x0A, 0x00, 0x00, 0x00, 0x5E, 0x00, 0x00, 0x00, 0x5B, 0x00, 0x00, 0x00,
0x5D, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x26, 0x00, 0x00, 0x00,
0x5F, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
0x3E, 0x00, 0x03, 0x00, 0x5F, 0x00, 0x00, 0x00, 0x5E, 0x00, 0x00, 0x00,
0x41, 0x00, 0x06, 0x00, 0x16, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00,
0x12, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
0x3D, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00,
0x60, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x2B, 0x00, 0x00, 0x00,
0x62, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
0x3E, 0x00, 0x03, 0x00, 0x62, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00,
0x3E, 0x00, 0x03, 0x00, 0x64, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
0xF9, 0x00, 0x02, 0x00, 0x65, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00,
0x65, 0x00, 0x00, 0x00, 0xF6, 0x00, 0x04, 0x00, 0x67, 0x00, 0x00, 0x00,
0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00,
0x69, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x69, 0x00, 0x00, 0x00,
0x3D, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0x6A, 0x00, 0x00, 0x00,
0x64, 0x00, 0x00, 0x00, 0xB1, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00,
0x6C, 0x00, 0x00, 0x00, 0x6A, 0x00, 0x00, 0x00, 0x6B, 0x00, 0x00, 0x00,
0xFA, 0x00, 0x04, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00,
0x67, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x66, 0x00, 0x00, 0x00,
0x3D, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0x6D, 0x00, 0x00, 0x00,
0x64, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00,
0x6E, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00,
0x23, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00, 0x6E, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x0A, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00,
0x7F, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00,
0x70, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00,
0x72, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00,
0x23, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00,
0x28, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x0A, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00,
0x81, 0x00, 0x05, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00,
0x71, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x13, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
0x41, 0x00, 0x06, 0x00, 0x23, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00,
0x33, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00,
0x3D, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00,
0x77, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x0A, 0x00, 0x00, 0x00,
0x79, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00,
0x41, 0x00, 0x05, 0x00, 0x26, 0x00, 0x00, 0x00, 0x7A, 0x00, 0x00, 0x00,
0x30, 0x00, 0x00, 0x00, 0x6D, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00,
0x7A, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00,
0x68, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x68, 0x00, 0x00, 0x00,
0x3D, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0x7B, 0x00, 0x00, 0x00,
0x64, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00, 0x13, 0x00, 0x00, 0x00,
0x7C, 0x00, 0x00, 0x00, 0x7B, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
0x3E, 0x00, 0x03, 0x00, 0x64, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00,
0xF9, 0x00, 0x02, 0x00, 0x65, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00,
0x67, 0x00, 0x00, 0x00, 0xDA, 0x00, 0x01, 0x00, 0xDB, 0x00, 0x01, 0x00,
0xF9, 0x00, 0x02, 0x00, 0x1F, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00,
0x7D, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x23, 0x00, 0x00, 0x00,
0x7E, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00,
0x7F, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00,
0x26, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x80, 0x00, 0x00, 0x00,
0x7F, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x16, 0x00, 0x00, 0x00,
0x81, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
0x28, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00,
0x82, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00,
0x2B, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
0x28, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x83, 0x00, 0x00, 0x00,
0x82, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x34, 0x00, 0x00, 0x00,
0x84, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
0x3D, 0x00, 0x04, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00,
0x84, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00,
0x85, 0x00, 0x00, 0x00, 0xDA, 0x00, 0x01, 0x00, 0x41, 0x00, 0x06, 0x00,
0x23, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
0x28, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x0A, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00,
0x41, 0x00, 0x05, 0x00, 0x26, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00,
0x22, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00,
0x88, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00,
0x16, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
0x28, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x09, 0x00, 0x00, 0x00, 0x8A, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00,
0x41, 0x00, 0x05, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x8B, 0x00, 0x00, 0x00,
0x22, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00,
0x8B, 0x00, 0x00, 0x00, 0x8A, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00,
0x34, 0x00, 0x00, 0x00, 0x8C, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00,
0x28, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x2E, 0x00, 0x00, 0x00,
0x8D, 0x00, 0x00, 0x00, 0x8C, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00,
0x30, 0x00, 0x00, 0x00, 0x8D, 0x00, 0x00, 0x00, 0xDA, 0x00, 0x01, 0x00,
0x41, 0x00, 0x06, 0x00, 0x23, 0x00, 0x00, 0x00, 0x8E, 0x00, 0x00, 0x00,
0x12, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
0x3D, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x8F, 0x00, 0x00, 0x00,
0x8E, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x26, 0x00, 0x00, 0x00,
0x90, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
0x3E, 0x00, 0x03, 0x00, 0x90, 0x00, 0x00, 0x00, 0x8F, 0x00, 0x00, 0x00,
0x41, 0x00, 0x06, 0x00, 0x16, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00,
0x12, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
0x3D, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00,
0x91, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x2B, 0x00, 0x00, 0x00,
0x93, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
0x3E, 0x00, 0x03, 0x00, 0x93, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00,
0x41, 0x00, 0x05, 0x00, 0x34, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00,
0x33, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x2E, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00,
0x3E, 0x00, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00,
0xDA, 0x00, 0x01, 0x00, 0xDB, 0x00, 0x01, 0x00, 0x41, 0x00, 0x06, 0x00,
0x23, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x0A, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00,
0x41, 0x00, 0x05, 0x00, 0x26, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00,
0x22, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00,
0x98, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00,
0x16, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x09, 0x00, 0x00, 0x00, 0x9A, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00,
0x41, 0x00, 0x05, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x9B, 0x00, 0x00, 0x00,
0x22, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00,
0x9B, 0x00, 0x00, 0x00, 0x9A, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00,
0x34, 0x00, 0x00, 0x00, 0x9C, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x2E, 0x00, 0x00, 0x00,
0x9D, 0x00, 0x00, 0x00, 0x9C, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00,
0x30, 0x00, 0x00, 0x00, 0x9D, 0x00, 0x00, 0x00, 0xDA, 0x00, 0x01, 0x00,
0x41, 0x00, 0x06, 0x00, 0x23, 0x00, 0x00, 0x00, 0x9E, 0x00, 0x00, 0x00,
0x12, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
0x3D, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x9F, 0x00, 0x00, 0x00,
0x9E, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x26, 0x00, 0x00, 0x00,
0xA0, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
0x3E, 0x00, 0x03, 0x00, 0xA0, 0x00, 0x00, 0x00, 0x9F, 0x00, 0x00, 0x00,
0x41, 0x00, 0x06, 0x00, 0x16, 0x00, 0x00, 0x00, 0xA1, 0x00, 0x00, 0x00,
0x12, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
0x3D, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0xA2, 0x00, 0x00, 0x00,
0xA1, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x2B, 0x00, 0x00, 0x00,
0xA3, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
0x3E, 0x00, 0x03, 0x00, 0xA3, 0x00, 0x00, 0x00, 0xA2, 0x00, 0x00, 0x00,
0x41, 0x00, 0x05, 0x00, 0x34, 0x00, 0x00, 0x00, 0xA4, 0x00, 0x00, 0x00,
0x33, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x2E, 0x00, 0x00, 0x00, 0xA5, 0x00, 0x00, 0x00, 0xA4, 0x00, 0x00, 0x00,
0x3E, 0x00, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00, 0xA5, 0x00, 0x00, 0x00,
0xDA, 0x00, 0x01, 0x00, 0x41, 0x00, 0x06, 0x00, 0x23, 0x00, 0x00, 0x00,
0xA6, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00,
0xA7, 0x00, 0x00, 0x00, 0xA6, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00,
0x23, 0x00, 0x00, 0x00, 0xA8, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
0x19, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x0A, 0x00, 0x00, 0x00, 0xA9, 0x00, 0x00, 0x00, 0xA8, 0x00, 0x00, 0x00,
0x81, 0x00, 0x05, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xAA, 0x00, 0x00, 0x00,
0xA7, 0x00, 0x00, 0x00, 0xA9, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00,
0x23, 0x00, 0x00, 0x00, 0xAB, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
0x28, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x0A, 0x00, 0x00, 0x00, 0xAC, 0x00, 0x00, 0x00, 0xAB, 0x00, 0x00, 0x00,
0x83, 0x00, 0x05, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xAD, 0x00, 0x00, 0x00,
0xAA, 0x00, 0x00, 0x00, 0xAC, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00,
0x26, 0x00, 0x00, 0x00, 0xAE, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0xAE, 0x00, 0x00, 0x00,
0xAD, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x16, 0x00, 0x00, 0x00,
0xAF, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,
0x28, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00,
0xB0, 0x00, 0x00, 0x00, 0xAF, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00,
0x2B, 0x00, 0x00, 0x00, 0xB1, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
0x28, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0xB1, 0x00, 0x00, 0x00,
0xB0, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0xB2, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, 0xB3, 0x00, 0x00, 0x00,
0xF8, 0x00, 0x02, 0x00, 0xB3, 0x00, 0x00, 0x00, 0xF6, 0x00, 0x04, 0x00,
0xB5, 0x00, 0x00, 0x00, 0xB6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xF9, 0x00, 0x02, 0x00, 0xB7, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00,
0xB7, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00,
0xB8, 0x00, 0x00, 0x00, 0xB2, 0x00, 0x00, 0x00, 0xB1, 0x00, 0x05, 0x00,
0x06, 0x00, 0x00, 0x00, 0xB9, 0x00, 0x00, 0x00, 0xB8, 0x00, 0x00, 0x00,
0x6B, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x04, 0x00, 0xB9, 0x00, 0x00, 0x00,
0xB4, 0x00, 0x00, 0x00, 0xB5, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00,
0xB4, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00,
0xBA, 0x00, 0x00, 0x00, 0xB2, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x13, 0x00, 0x00, 0x00, 0xBB, 0x00, 0x00, 0x00, 0xB2, 0x00, 0x00, 0x00,
0x41, 0x00, 0x06, 0x00, 0x23, 0x00, 0x00, 0x00, 0xBC, 0x00, 0x00, 0x00,
0x33, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xBB, 0x00, 0x00, 0x00,
0x3D, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xBD, 0x00, 0x00, 0x00,
0xBC, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00,
0xBE, 0x00, 0x00, 0x00, 0xB2, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00,
0x23, 0x00, 0x00, 0x00, 0xBF, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00,
0x28, 0x00, 0x00, 0x00, 0xBE, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x0A, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xBF, 0x00, 0x00, 0x00,
0x7F, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0x00,
0xC0, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x0A, 0x00, 0x00, 0x00,
0xC2, 0x00, 0x00, 0x00, 0xBD, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0x00,
0x3D, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00,
0xB2, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x23, 0x00, 0x00, 0x00,
0xC4, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,
0xC3, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00,
0xC5, 0x00, 0x00, 0x00, 0xC4, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00,
0x0A, 0x00, 0x00, 0x00, 0xC6, 0x00, 0x00, 0x00, 0xC2, 0x00, 0x00, 0x00,
0xC5, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x26, 0x00, 0x00, 0x00,
0xC7, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0xBA, 0x00, 0x00, 0x00,
0x3E, 0x00, 0x03, 0x00, 0xC7, 0x00, 0x00, 0x00, 0xC6, 0x00, 0x00, 0x00,
0xF9, 0x00, 0x02, 0x00, 0xB6, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00,
0xB6, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00,
0xC8, 0x00, 0x00, 0x00, 0xB2, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00,
0x13, 0x00, 0x00, 0x00, 0xC9, 0x00, 0x00, 0x00, 0xC8, 0x00, 0x00, 0x00,
0x28, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0xB2, 0x00, 0x00, 0x00,
0xC9, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, 0xB3, 0x00, 0x00, 0x00,
0xF8, 0x00, 0x02, 0x00, 0xB5, 0x00, 0x00, 0x00, 0xDA, 0x00, 0x01, 0x00,
0xDB, 0x00, 0x01, 0x00, 0xF9, 0x00, 0x02, 0x00, 0x1F, 0x00, 0x00, 0x00,
0xF8, 0x00, 0x02, 0x00, 0x1F, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x01, 0x00,
0x38, 0x00, 0x01, 0x00,
};

View File

@@ -0,0 +1,317 @@
; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 1
; Bound: 202
; Schema: 0
OpCapability Geometry
OpCapability GeometryPointSize
OpCapability ClipDistance
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Geometry %4 "main" %18 %34 %48 %51
OpExecutionMode %4 Triangles
OpExecutionMode %4 Invocations 1
OpExecutionMode %4 OutputTriangleStrip
OpExecutionMode %4 OutputVertices 6
OpSource GLSL 450
OpName %4 "main"
OpName %8 "left_aligned"
OpName %14 "gl_PerVertex"
OpMemberName %14 0 "gl_Position"
OpMemberName %14 1 "gl_PointSize"
OpMemberName %14 2 "gl_ClipDistance"
OpName %18 "gl_in"
OpName %32 "gl_PerVertex"
OpMemberName %32 0 "gl_Position"
OpMemberName %32 1 "gl_PointSize"
OpMemberName %32 2 "gl_ClipDistance"
OpName %34 ""
OpName %48 "out_interpolators"
OpName %51 "in_interpolators"
OpName %100 "i"
OpName %178 "i"
OpMemberDecorate %14 0 BuiltIn Position
OpMemberDecorate %14 1 BuiltIn PointSize
OpMemberDecorate %14 2 BuiltIn ClipDistance
OpDecorate %14 Block
OpMemberDecorate %32 0 BuiltIn Position
OpMemberDecorate %32 1 BuiltIn PointSize
OpMemberDecorate %32 2 BuiltIn ClipDistance
OpDecorate %32 Block
OpDecorate %48 Location 0
OpDecorate %51 Location 0
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeBool
%7 = OpTypePointer Function %6
%9 = OpTypeFloat 32
%10 = OpTypeVector %9 4
%11 = OpTypeInt 32 0
%12 = OpConstant %11 1
%13 = OpTypeArray %9 %12
%14 = OpTypeStruct %10 %9 %13
%15 = OpConstant %11 3
%16 = OpTypeArray %14 %15
%17 = OpTypePointer Input %16
%18 = OpVariable %17 Input
%19 = OpTypeInt 32 1
%20 = OpConstant %19 0
%21 = OpConstant %11 0
%22 = OpTypePointer Input %9
%25 = OpConstant %19 2
%32 = OpTypeStruct %10 %9 %13
%33 = OpTypePointer Output %32
%34 = OpVariable %33 Output
%35 = OpTypePointer Input %10
%38 = OpTypePointer Output %10
%40 = OpConstant %19 1
%43 = OpTypePointer Output %9
%45 = OpConstant %11 16
%46 = OpTypeArray %10 %45
%47 = OpTypePointer Output %46
%48 = OpVariable %47 Output
%49 = OpTypeArray %46 %15
%50 = OpTypePointer Input %49
%51 = OpVariable %50 Input
%52 = OpTypePointer Input %46
%99 = OpTypePointer Function %19
%107 = OpConstant %19 16
%4 = OpFunction %2 None %3
%5 = OpLabel
%8 = OpVariable %7 Function
%100 = OpVariable %99 Function
%178 = OpVariable %99 Function
%23 = OpAccessChain %22 %18 %20 %20 %21
%24 = OpLoad %9 %23
%26 = OpAccessChain %22 %18 %25 %20 %21
%27 = OpLoad %9 %26
%28 = OpFOrdEqual %6 %24 %27
OpStore %8 %28
%29 = OpLoad %6 %8
OpSelectionMerge %31 None
OpBranchConditional %29 %30 %125
%30 = OpLabel
%36 = OpAccessChain %35 %18 %20 %20
%37 = OpLoad %10 %36
%39 = OpAccessChain %38 %34 %20
OpStore %39 %37
%41 = OpAccessChain %22 %18 %20 %40
%42 = OpLoad %9 %41
%44 = OpAccessChain %43 %34 %40
OpStore %44 %42
%53 = OpAccessChain %52 %51 %20
%54 = OpLoad %46 %53
OpStore %48 %54
OpEmitVertex
%55 = OpAccessChain %35 %18 %40 %20
%56 = OpLoad %10 %55
%57 = OpAccessChain %38 %34 %20
OpStore %57 %56
%58 = OpAccessChain %22 %18 %40 %40
%59 = OpLoad %9 %58
%60 = OpAccessChain %43 %34 %40
OpStore %60 %59
%61 = OpAccessChain %52 %51 %40
%62 = OpLoad %46 %61
OpStore %48 %62
OpEmitVertex
%63 = OpAccessChain %35 %18 %25 %20
%64 = OpLoad %10 %63
%65 = OpAccessChain %38 %34 %20
OpStore %65 %64
%66 = OpAccessChain %22 %18 %25 %40
%67 = OpLoad %9 %66
%68 = OpAccessChain %43 %34 %40
OpStore %68 %67
%69 = OpAccessChain %52 %51 %25
%70 = OpLoad %46 %69
OpStore %48 %70
OpEmitVertex
OpEndPrimitive
%71 = OpAccessChain %35 %18 %25 %20
%72 = OpLoad %10 %71
%73 = OpAccessChain %38 %34 %20
OpStore %73 %72
%74 = OpAccessChain %22 %18 %25 %40
%75 = OpLoad %9 %74
%76 = OpAccessChain %43 %34 %40
OpStore %76 %75
%77 = OpAccessChain %52 %51 %25
%78 = OpLoad %46 %77
OpStore %48 %78
OpEmitVertex
%79 = OpAccessChain %35 %18 %40 %20
%80 = OpLoad %10 %79
%81 = OpAccessChain %38 %34 %20
OpStore %81 %80
%82 = OpAccessChain %22 %18 %40 %40
%83 = OpLoad %9 %82
%84 = OpAccessChain %43 %34 %40
OpStore %84 %83
%85 = OpAccessChain %52 %51 %40
%86 = OpLoad %46 %85
OpStore %48 %86
OpEmitVertex
%87 = OpAccessChain %35 %18 %40 %20
%88 = OpLoad %10 %87
%89 = OpAccessChain %35 %18 %25 %20
%90 = OpLoad %10 %89
%91 = OpFAdd %10 %88 %90
%92 = OpAccessChain %35 %18 %20 %20
%93 = OpLoad %10 %92
%94 = OpFSub %10 %91 %93
%95 = OpAccessChain %38 %34 %20
OpStore %95 %94
%96 = OpAccessChain %22 %18 %25 %40
%97 = OpLoad %9 %96
%98 = OpAccessChain %43 %34 %40
OpStore %98 %97
OpStore %100 %20
OpBranch %101
%101 = OpLabel
OpLoopMerge %103 %104 None
OpBranch %105
%105 = OpLabel
%106 = OpLoad %19 %100
%108 = OpSLessThan %6 %106 %107
OpBranchConditional %108 %102 %103
%102 = OpLabel
%109 = OpLoad %19 %100
%110 = OpLoad %19 %100
%111 = OpAccessChain %35 %51 %20 %110
%112 = OpLoad %10 %111
%113 = OpFNegate %10 %112
%114 = OpLoad %19 %100
%115 = OpAccessChain %35 %51 %40 %114
%116 = OpLoad %10 %115
%117 = OpFAdd %10 %113 %116
%118 = OpLoad %19 %100
%119 = OpAccessChain %35 %51 %25 %118
%120 = OpLoad %10 %119
%121 = OpFAdd %10 %117 %120
%122 = OpAccessChain %38 %48 %109
OpStore %122 %121
OpBranch %104
%104 = OpLabel
%123 = OpLoad %19 %100
%124 = OpIAdd %19 %123 %40
OpStore %100 %124
OpBranch %101
%103 = OpLabel
OpEmitVertex
OpEndPrimitive
OpBranch %31
%125 = OpLabel
%126 = OpAccessChain %35 %18 %20 %20
%127 = OpLoad %10 %126
%128 = OpAccessChain %38 %34 %20
OpStore %128 %127
%129 = OpAccessChain %22 %18 %20 %40
%130 = OpLoad %9 %129
%131 = OpAccessChain %43 %34 %40
OpStore %131 %130
%132 = OpAccessChain %52 %51 %20
%133 = OpLoad %46 %132
OpStore %48 %133
OpEmitVertex
%134 = OpAccessChain %35 %18 %40 %20
%135 = OpLoad %10 %134
%136 = OpAccessChain %38 %34 %20
OpStore %136 %135
%137 = OpAccessChain %22 %18 %40 %40
%138 = OpLoad %9 %137
%139 = OpAccessChain %43 %34 %40
OpStore %139 %138
%140 = OpAccessChain %52 %51 %40
%141 = OpLoad %46 %140
OpStore %48 %141
OpEmitVertex
%142 = OpAccessChain %35 %18 %25 %20
%143 = OpLoad %10 %142
%144 = OpAccessChain %38 %34 %20
OpStore %144 %143
%145 = OpAccessChain %22 %18 %25 %40
%146 = OpLoad %9 %145
%147 = OpAccessChain %43 %34 %40
OpStore %147 %146
%148 = OpAccessChain %52 %51 %25
%149 = OpLoad %46 %148
OpStore %48 %149
OpEmitVertex
OpEndPrimitive
%150 = OpAccessChain %35 %18 %20 %20
%151 = OpLoad %10 %150
%152 = OpAccessChain %38 %34 %20
OpStore %152 %151
%153 = OpAccessChain %22 %18 %20 %40
%154 = OpLoad %9 %153
%155 = OpAccessChain %43 %34 %40
OpStore %155 %154
%156 = OpAccessChain %52 %51 %20
%157 = OpLoad %46 %156
OpStore %48 %157
OpEmitVertex
%158 = OpAccessChain %35 %18 %25 %20
%159 = OpLoad %10 %158
%160 = OpAccessChain %38 %34 %20
OpStore %160 %159
%161 = OpAccessChain %22 %18 %25 %40
%162 = OpLoad %9 %161
%163 = OpAccessChain %43 %34 %40
OpStore %163 %162
%164 = OpAccessChain %52 %51 %25
%165 = OpLoad %46 %164
OpStore %48 %165
OpEmitVertex
%166 = OpAccessChain %35 %18 %20 %20
%167 = OpLoad %10 %166
%168 = OpAccessChain %35 %18 %25 %20
%169 = OpLoad %10 %168
%170 = OpFAdd %10 %167 %169
%171 = OpAccessChain %35 %18 %40 %20
%172 = OpLoad %10 %171
%173 = OpFSub %10 %170 %172
%174 = OpAccessChain %38 %34 %20
OpStore %174 %173
%175 = OpAccessChain %22 %18 %25 %40
%176 = OpLoad %9 %175
%177 = OpAccessChain %43 %34 %40
OpStore %177 %176
OpStore %178 %20
OpBranch %179
%179 = OpLabel
OpLoopMerge %181 %182 None
OpBranch %183
%183 = OpLabel
%184 = OpLoad %19 %178
%185 = OpSLessThan %6 %184 %107
OpBranchConditional %185 %180 %181
%180 = OpLabel
%186 = OpLoad %19 %178
%187 = OpLoad %19 %178
%188 = OpAccessChain %35 %51 %20 %187
%189 = OpLoad %10 %188
%190 = OpLoad %19 %178
%191 = OpAccessChain %35 %51 %40 %190
%192 = OpLoad %10 %191
%193 = OpFNegate %10 %192
%194 = OpFAdd %10 %189 %193
%195 = OpLoad %19 %178
%196 = OpAccessChain %35 %51 %25 %195
%197 = OpLoad %10 %196
%198 = OpFAdd %10 %194 %197
%199 = OpAccessChain %38 %48 %186
OpStore %199 %198
OpBranch %182
%182 = OpLabel
%200 = OpLoad %19 %178
%201 = OpIAdd %19 %200 %40
OpStore %178 %201
OpBranch %179
%181 = OpLabel
OpEmitVertex
OpEndPrimitive
OpBranch %31
%31 = OpLabel
OpReturn
OpFunctionEnd

View File

@@ -0,0 +1,46 @@
// NOTE: This file is compiled and embedded into the exe.
// Use `xenia-build genspirv` and check in any changes under bin/.
#version 450 core
#extension all : warn
in gl_PerVertex {
vec4 gl_Position;
float gl_PointSize;
float gl_ClipDistance[];
} gl_in[];
out gl_PerVertex {
vec4 gl_Position;
float gl_PointSize;
float gl_ClipDistance[];
};
layout(location = 0) in vec4 in_interpolators[][16];
layout(location = 0) out vec4 out_interpolators[16];
layout(lines_adjacency) in;
layout(line_strip, max_vertices = 5) out;
void main() {
gl_Position = gl_in[0].gl_Position;
gl_PointSize = gl_in[0].gl_PointSize;
out_interpolators = in_interpolators[0];
EmitVertex();
gl_Position = gl_in[1].gl_Position;
gl_PointSize = gl_in[1].gl_PointSize;
out_interpolators = in_interpolators[1];
EmitVertex();
gl_Position = gl_in[2].gl_Position;
gl_PointSize = gl_in[2].gl_PointSize;
out_interpolators = in_interpolators[2];
EmitVertex();
gl_Position = gl_in[3].gl_Position;
gl_PointSize = gl_in[3].gl_PointSize;
out_interpolators = in_interpolators[3];
EmitVertex();
gl_Position = gl_in[0].gl_Position;
gl_PointSize = gl_in[0].gl_PointSize;
out_interpolators = in_interpolators[0];
EmitVertex();
EndPrimitive();
}

View File

@@ -0,0 +1,48 @@
// NOTE: This file is compiled and embedded into the exe.
// Use `xenia-build genspirv` and check in any changes under bin/.
#version 450 core
#extension all : warn
in gl_PerVertex {
vec4 gl_Position;
float gl_PointSize;
float gl_ClipDistance[];
} gl_in[];
out gl_PerVertex {
vec4 gl_Position;
float gl_PointSize;
float gl_ClipDistance[];
};
struct VertexData {
vec4 o[16];
};
layout(location = 0) in VertexData in_vtx[];
layout(location = 0) out VertexData out_vtx;
// TODO(benvanik): fetch default point size from register and use that if
// the VS doesn't write oPointSize.
// TODO(benvanik): clamp to min/max.
// TODO(benvanik): figure out how to see which interpolator gets adjusted.
layout(points) in;
layout(triangle_strip, max_vertices = 4) out;
void main() {
const vec2 offsets[4] = {
vec2(-1.0, 1.0),
vec2( 1.0, 1.0),
vec2(-1.0, -1.0),
vec2( 1.0, -1.0),
};
vec4 pos = gl_in[0].gl_Position;
float psize = gl_in[0].gl_PointSize;
for (int i = 0; i < 4; ++i) {
gl_Position = vec4(pos.xy + offsets[i] * psize, pos.zw);
out_vtx = in_vtx[0];
EmitVertex();
}
EndPrimitive();
}

View File

@@ -0,0 +1,34 @@
// NOTE: This file is compiled and embedded into the exe.
// Use `xenia-build genspirv` and check in any changes under bin/.
#version 450 core
#extension all : warn
in gl_PerVertex {
vec4 gl_Position;
float gl_PointSize;
float gl_ClipDistance[];
} gl_in[];
out gl_PerVertex {
vec4 gl_Position;
float gl_PointSize;
float gl_ClipDistance[];
};
layout(location = 0) in vec4 in_interpolators[][16];
layout(location = 0) out vec4 out_interpolators[16];
layout(lines_adjacency) in;
layout(triangle_strip, max_vertices = 4) out;
void main() {
const int order[4] = { 0, 1, 3, 2 };
for (int i = 0; i < 4; ++i) {
int input_index = order[i];
gl_Position = gl_in[input_index].gl_Position;
gl_PointSize = gl_in[input_index].gl_PointSize;
out_interpolators = in_interpolators[input_index];
EmitVertex();
}
EndPrimitive();
}

View File

@@ -0,0 +1,98 @@
// NOTE: This file is compiled and embedded into the exe.
// Use `xenia-build genspirv` and check in any changes under bin/.
#version 450 core
#extension all : warn
in gl_PerVertex {
vec4 gl_Position;
float gl_PointSize;
float gl_ClipDistance[];
} gl_in[];
out gl_PerVertex {
vec4 gl_Position;
float gl_PointSize;
float gl_ClipDistance[];
};
layout(location = 0) in vec4 in_interpolators[][16];
layout(location = 0) out vec4 out_interpolators[16];
layout(triangles) in;
layout(triangle_strip, max_vertices = 6) out;
void main() {
// Most games use the left-aligned form.
bool left_aligned = gl_in[0].gl_Position.x == gl_in[2].gl_Position.x;
if (left_aligned) {
// 0 ------ 1
// | - |
// | // |
// | - |
// 2 ----- [3]
gl_Position = gl_in[0].gl_Position;
gl_PointSize = gl_in[0].gl_PointSize;
out_interpolators = in_interpolators[0];
EmitVertex();
gl_Position = gl_in[1].gl_Position;
gl_PointSize = gl_in[1].gl_PointSize;
out_interpolators = in_interpolators[1];
EmitVertex();
gl_Position = gl_in[2].gl_Position;
gl_PointSize = gl_in[2].gl_PointSize;
out_interpolators = in_interpolators[2];
EmitVertex();
EndPrimitive();
gl_Position = gl_in[2].gl_Position;
gl_PointSize = gl_in[2].gl_PointSize;
out_interpolators = in_interpolators[2];
EmitVertex();
gl_Position = gl_in[1].gl_Position;
gl_PointSize = gl_in[1].gl_PointSize;
out_interpolators = in_interpolators[1];
EmitVertex();
gl_Position = (gl_in[1].gl_Position + gl_in[2].gl_Position) -
gl_in[0].gl_Position;
gl_PointSize = gl_in[2].gl_PointSize;
for (int i = 0; i < 16; ++i) {
out_interpolators[i] = -in_interpolators[0][i] + in_interpolators[1][i] + in_interpolators[2][i];
}
EmitVertex();
EndPrimitive();
} else {
// 0 ------ 1
// | - |
// | \\ |
// | - |
// [3] ----- 2
gl_Position = gl_in[0].gl_Position;
gl_PointSize = gl_in[0].gl_PointSize;
out_interpolators = in_interpolators[0];
EmitVertex();
gl_Position = gl_in[1].gl_Position;
gl_PointSize = gl_in[1].gl_PointSize;
out_interpolators = in_interpolators[1];
EmitVertex();
gl_Position = gl_in[2].gl_Position;
gl_PointSize = gl_in[2].gl_PointSize;
out_interpolators = in_interpolators[2];
EmitVertex();
EndPrimitive();
gl_Position = gl_in[0].gl_Position;
gl_PointSize = gl_in[0].gl_PointSize;
out_interpolators = in_interpolators[0];
EmitVertex();
gl_Position = gl_in[2].gl_Position;
gl_PointSize = gl_in[2].gl_PointSize;
out_interpolators = in_interpolators[2];
EmitVertex();
gl_Position = (gl_in[0].gl_Position + gl_in[2].gl_Position) -
gl_in[1].gl_Position;
gl_PointSize = gl_in[2].gl_PointSize;
for (int i = 0; i < 16; ++i) {
out_interpolators[i] = in_interpolators[0][i] + -in_interpolators[1][i] + in_interpolators[2][i];
}
EmitVertex();
EndPrimitive();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,207 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2016 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_GPU_VULKAN_TEXTURE_CACHE_H_
#define XENIA_GPU_VULKAN_TEXTURE_CACHE_H_
#include <unordered_map>
#include "xenia/gpu/register_file.h"
#include "xenia/gpu/sampler_info.h"
#include "xenia/gpu/shader.h"
#include "xenia/gpu/texture_info.h"
#include "xenia/gpu/trace_writer.h"
#include "xenia/gpu/vulkan/vulkan_command_processor.h"
#include "xenia/gpu/xenos.h"
#include "xenia/ui/vulkan/circular_buffer.h"
#include "xenia/ui/vulkan/vulkan.h"
#include "xenia/ui/vulkan/vulkan_device.h"
namespace xe {
namespace gpu {
namespace vulkan {
//
class TextureCache {
public:
struct TextureView;
// This represents an uploaded Vulkan texture.
struct Texture {
TextureInfo texture_info;
std::vector<std::unique_ptr<TextureView>> views;
// True if we know all info about this texture, false otherwise.
// (e.g. we resolve to system memory and may not know the full details about
// this texture)
bool is_full_texture;
VkFormat format;
VkImage image;
VkImageLayout image_layout;
VkDeviceMemory image_memory;
VkDeviceSize memory_offset;
VkDeviceSize memory_size;
uintptr_t access_watch_handle;
bool pending_invalidation;
// Pointer to the latest usage fence.
std::shared_ptr<ui::vulkan::Fence> in_flight_fence;
};
struct TextureView {
Texture* texture;
VkImageView view;
union {
struct {
// FIXME: This only applies on little-endian platforms!
uint16_t swiz_x : 3;
uint16_t swiz_y : 3;
uint16_t swiz_z : 3;
uint16_t swiz_w : 3;
uint16_t : 4;
};
uint16_t swizzle;
};
};
TextureCache(Memory* memory, RegisterFile* register_file,
TraceWriter* trace_writer, ui::vulkan::VulkanDevice* device);
~TextureCache();
// Descriptor set layout containing all possible texture bindings.
// The set contains one descriptor for each texture sampler [0-31].
VkDescriptorSetLayout texture_descriptor_set_layout() const {
return texture_descriptor_set_layout_;
}
// Prepares a descriptor set containing the samplers and images for all
// bindings. The textures will be uploaded/converted/etc as needed.
// Requires a fence to be provided that will be signaled when finished
// using the returned descriptor set.
VkDescriptorSet PrepareTextureSet(
VkCommandBuffer setup_command_buffer,
std::shared_ptr<ui::vulkan::Fence> completion_fence,
const std::vector<Shader::TextureBinding>& vertex_bindings,
const std::vector<Shader::TextureBinding>& pixel_bindings);
// TODO(benvanik): UploadTexture.
// TODO(benvanik): Resolve.
// TODO(benvanik): ReadTexture.
// Looks for a texture either containing or matching these parameters.
// Caller is responsible for checking if the texture returned is an exact
// match or just contains the texture given by the parameters.
// If offset_x and offset_y are not null, this may return a texture that
// contains this address at an offset.
Texture* LookupAddress(uint32_t guest_address, uint32_t width,
uint32_t height, TextureFormat format,
VkOffset2D* out_offset = nullptr);
// Demands a texture for the purpose of resolving from EDRAM. This either
// creates a new texture or returns a previously created texture. texture_info
// is not required to be completely filled out, just guest_address and all
// sizes.
//
// It's possible that this may return an image that is larger than the
// requested size (e.g. resolving into a bigger texture) or an image that
// must have an offset applied. If so, the caller must handle this.
// At the very least, it's guaranteed that the image will be large enough to
// hold the requested size.
Texture* DemandResolveTexture(const TextureInfo& texture_info,
TextureFormat format, VkOffset2D* out_offset);
// Clears all cached content.
void ClearCache();
// Frees any unused resources
void Scavenge();
private:
struct UpdateSetInfo;
// Cached Vulkan sampler.
struct Sampler {
SamplerInfo sampler_info;
VkSampler sampler;
};
// Allocates a new texture and memory to back it on the GPU.
Texture* AllocateTexture(const TextureInfo& texture_info);
bool FreeTexture(Texture* texture);
// Demands a texture. If command_buffer is null and the texture hasn't been
// uploaded to graphics memory already, we will return null and bail.
Texture* Demand(
const TextureInfo& texture_info, VkCommandBuffer command_buffer = nullptr,
std::shared_ptr<ui::vulkan::Fence> completion_fence = nullptr);
TextureView* DemandView(Texture* texture, uint16_t swizzle);
Sampler* Demand(const SamplerInfo& sampler_info);
// Queues commands to upload a texture from system memory, applying any
// conversions necessary. This may flush the command buffer to the GPU if we
// run out of staging memory.
bool UploadTexture2D(VkCommandBuffer command_buffer,
std::shared_ptr<ui::vulkan::Fence> completion_fence,
Texture* dest, TextureInfo src);
bool SetupTextureBindings(
VkCommandBuffer command_buffer,
std::shared_ptr<ui::vulkan::Fence> completion_fence,
UpdateSetInfo* update_set_info,
const std::vector<Shader::TextureBinding>& bindings);
bool SetupTextureBinding(VkCommandBuffer command_buffer,
std::shared_ptr<ui::vulkan::Fence> completion_fence,
UpdateSetInfo* update_set_info,
const Shader::TextureBinding& binding);
Memory* memory_ = nullptr;
RegisterFile* register_file_ = nullptr;
TraceWriter* trace_writer_ = nullptr;
ui::vulkan::VulkanDevice* device_ = nullptr;
VkDescriptorPool descriptor_pool_ = nullptr;
VkDescriptorSetLayout texture_descriptor_set_layout_ = nullptr;
std::list<std::pair<VkDescriptorSet, std::shared_ptr<ui::vulkan::Fence>>>
in_flight_sets_;
ui::vulkan::CircularBuffer staging_buffer_;
std::unordered_map<uint64_t, Texture*> textures_;
std::unordered_map<uint64_t, Sampler*> samplers_;
std::vector<Texture*> resolve_textures_;
std::list<Texture*> pending_delete_textures_;
std::mutex invalidated_textures_mutex_;
std::vector<Texture*>* invalidated_textures_;
std::vector<Texture*> invalidated_textures_sets_[2];
std::mutex invalidated_resolve_textures_mutex_;
std::vector<Texture*> invalidated_resolve_textures_;
struct UpdateSetInfo {
// Bitmap of all 32 fetch constants and whether they have been setup yet.
// This prevents duplication across the vertex and pixel shader.
uint32_t has_setup_fetch_mask;
uint32_t image_write_count = 0;
struct ImageSetInfo {
Dimension dimension;
uint32_t tf_binding;
VkDescriptorImageInfo info;
} image_infos[32];
} update_set_info_;
};
} // namespace vulkan
} // namespace gpu
} // namespace xe
#endif // XENIA_GPU_VULKAN_TEXTURE_CACHE_H_

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,126 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2016 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_GPU_VULKAN_VULKAN_COMMAND_PROCESSOR_H_
#define XENIA_GPU_VULKAN_VULKAN_COMMAND_PROCESSOR_H_
#include <atomic>
#include <cstring>
#include <functional>
#include <memory>
#include <mutex>
#include <queue>
#include <string>
#include <unordered_map>
#include <vector>
#include "xenia/base/threading.h"
#include "xenia/gpu/command_processor.h"
#include "xenia/gpu/register_file.h"
#include "xenia/gpu/vulkan/buffer_cache.h"
#include "xenia/gpu/vulkan/pipeline_cache.h"
#include "xenia/gpu/vulkan/render_cache.h"
#include "xenia/gpu/vulkan/texture_cache.h"
#include "xenia/gpu/vulkan/vulkan_shader.h"
#include "xenia/gpu/xenos.h"
#include "xenia/kernel/xthread.h"
#include "xenia/memory.h"
#include "xenia/ui/vulkan/fenced_pools.h"
#include "xenia/ui/vulkan/vulkan_context.h"
#include "xenia/ui/vulkan/vulkan_device.h"
#include "xenia/ui/vulkan/vulkan_util.h"
namespace xe {
namespace gpu {
namespace vulkan {
class VulkanGraphicsSystem;
class TextureCache;
class VulkanCommandProcessor : public CommandProcessor {
public:
VulkanCommandProcessor(VulkanGraphicsSystem* graphics_system,
kernel::KernelState* kernel_state);
~VulkanCommandProcessor() override;
virtual void RequestFrameTrace(const std::wstring& root_path) override;
void ClearCaches() override;
RenderCache* render_cache() { return render_cache_.get(); }
private:
bool SetupContext() override;
void ShutdownContext() override;
void MakeCoherent() override;
void PrepareForWait() override;
void ReturnFromWait() override;
void CreateSwapImages(VkCommandBuffer setup_buffer, VkExtent2D extents);
void DestroySwapImages();
void PerformSwap(uint32_t frontbuffer_ptr, uint32_t frontbuffer_width,
uint32_t frontbuffer_height) override;
Shader* LoadShader(ShaderType shader_type, uint32_t guest_address,
const uint32_t* host_address,
uint32_t dword_count) override;
bool IssueDraw(PrimitiveType primitive_type, uint32_t index_count,
IndexBufferInfo* index_buffer_info) override;
bool PopulateConstants(VkCommandBuffer command_buffer,
VulkanShader* vertex_shader,
VulkanShader* pixel_shader);
bool PopulateIndexBuffer(VkCommandBuffer command_buffer,
IndexBufferInfo* index_buffer_info);
bool PopulateVertexBuffers(VkCommandBuffer command_buffer,
VulkanShader* vertex_shader);
bool PopulateSamplers(VkCommandBuffer command_buffer,
VkCommandBuffer setup_buffer,
VulkanShader* vertex_shader,
VulkanShader* pixel_shader);
bool IssueCopy() override;
xe::ui::vulkan::VulkanDevice* device_ = nullptr;
// front buffer / back buffer memory
VkDeviceMemory fb_memory = nullptr;
VkDeviceMemory bb_memory = nullptr;
// TODO(benvanik): abstract behind context?
// Queue used to submit work. This may be a dedicated queue for the command
// processor and no locking will be required for use. If a dedicated queue
// was not available this will be the device primary_queue and the
// queue_mutex must be used to synchronize access to it.
VkQueue queue_ = nullptr;
std::mutex* queue_mutex_ = nullptr;
// Last copy base address, for debugging only.
uint32_t last_copy_base_ = 0;
bool capturing_ = false;
bool trace_requested_ = false;
std::unique_ptr<BufferCache> buffer_cache_;
std::unique_ptr<PipelineCache> pipeline_cache_;
std::unique_ptr<RenderCache> render_cache_;
std::unique_ptr<TextureCache> texture_cache_;
std::unique_ptr<ui::vulkan::CommandBufferPool> command_buffer_pool_;
const RenderState* current_render_state_ = nullptr;
VkCommandBuffer current_command_buffer_ = nullptr;
VkCommandBuffer current_setup_buffer_ = nullptr;
std::shared_ptr<ui::vulkan::Fence> current_batch_fence_;
};
} // namespace vulkan
} // namespace gpu
} // namespace xe
#endif // XENIA_GPU_VULKAN_VULKAN_COMMAND_PROCESSOR_H_

View File

@@ -0,0 +1,16 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2016 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "xenia/gpu/vulkan/vulkan_gpu_flags.h"
DEFINE_bool(vulkan_renderdoc_capture_all, false,
"Capture everything with RenderDoc.");
DEFINE_bool(vulkan_native_msaa, false, "Use native MSAA");
DEFINE_bool(vulkan_dump_disasm, false,
"Dump shader disassembly. NVIDIA only supported.");

View File

@@ -0,0 +1,21 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2016 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_GPU_VULKAN_VULKAN_GPU_FLAGS_H_
#define XENIA_GPU_VULKAN_VULKAN_GPU_FLAGS_H_
#include <gflags/gflags.h>
#define FINE_GRAINED_DRAW_SCOPES 1
DECLARE_bool(vulkan_renderdoc_capture_all);
DECLARE_bool(vulkan_native_msaa);
DECLARE_bool(vulkan_dump_disasm);
#endif // XENIA_GPU_VULKAN_VULKAN_GPU_FLAGS_H_

View File

@@ -0,0 +1,116 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2016 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "xenia/gpu/vulkan/vulkan_graphics_system.h"
#include <algorithm>
#include <cstring>
#include "xenia/base/logging.h"
#include "xenia/base/profiling.h"
#include "xenia/cpu/processor.h"
#include "xenia/gpu/gpu_flags.h"
#include "xenia/gpu/vulkan/vulkan_command_processor.h"
#include "xenia/gpu/vulkan/vulkan_gpu_flags.h"
#include "xenia/ui/vulkan/vulkan_provider.h"
#include "xenia/ui/vulkan/vulkan_swap_chain.h"
#include "xenia/ui/window.h"
namespace xe {
namespace gpu {
namespace vulkan {
VulkanGraphicsSystem::VulkanGraphicsSystem() {}
VulkanGraphicsSystem::~VulkanGraphicsSystem() = default;
X_STATUS VulkanGraphicsSystem::Setup(cpu::Processor* processor,
kernel::KernelState* kernel_state,
ui::Window* target_window) {
// Must create the provider so we can create contexts.
provider_ = xe::ui::vulkan::VulkanProvider::Create(target_window);
auto result = GraphicsSystem::Setup(processor, kernel_state, target_window);
if (result) {
return result;
}
display_context_ = reinterpret_cast<xe::ui::vulkan::VulkanContext*>(
target_window->context());
return X_STATUS_SUCCESS;
}
void VulkanGraphicsSystem::Shutdown() { GraphicsSystem::Shutdown(); }
std::unique_ptr<CommandProcessor>
VulkanGraphicsSystem::CreateCommandProcessor() {
return std::unique_ptr<CommandProcessor>(
new VulkanCommandProcessor(this, kernel_state_));
}
void VulkanGraphicsSystem::Swap(xe::ui::UIEvent* e) {
if (!command_processor_) {
return;
}
// Check for pending swap.
auto& swap_state = command_processor_->swap_state();
{
std::lock_guard<std::mutex> lock(swap_state.mutex);
if (swap_state.pending) {
swap_state.pending = false;
std::swap(swap_state.front_buffer_texture,
swap_state.back_buffer_texture);
}
}
if (!swap_state.front_buffer_texture) {
// Not yet ready.
return;
}
auto swap_chain = display_context_->swap_chain();
auto copy_cmd_buffer = swap_chain->copy_cmd_buffer();
auto front_buffer =
reinterpret_cast<VkImage>(swap_state.front_buffer_texture);
VkImageMemoryBarrier barrier;
std::memset(&barrier, 0, sizeof(VkImageMemoryBarrier));
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
barrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.image = front_buffer;
barrier.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
vkCmdPipelineBarrier(copy_cmd_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0,
nullptr, 1, &barrier);
VkImageBlit region;
region.srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
region.srcOffsets[0] = {0, 0, 0};
region.srcOffsets[1] = {static_cast<int32_t>(swap_state.width),
static_cast<int32_t>(swap_state.height), 1};
region.dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
region.dstOffsets[0] = {0, 0, 0};
region.dstOffsets[1] = {static_cast<int32_t>(swap_chain->surface_width()),
static_cast<int32_t>(swap_chain->surface_height()),
1};
vkCmdBlitImage(copy_cmd_buffer, front_buffer, VK_IMAGE_LAYOUT_GENERAL,
swap_chain->surface_image(),
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region,
VK_FILTER_LINEAR);
}
} // namespace vulkan
} // namespace gpu
} // namespace xe

View File

@@ -0,0 +1,43 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2016 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_GPU_VULKAN_VULKAN_GRAPHICS_SYSTEM_H_
#define XENIA_GPU_VULKAN_VULKAN_GRAPHICS_SYSTEM_H_
#include <memory>
#include "xenia/gpu/graphics_system.h"
#include "xenia/ui/vulkan/vulkan_context.h"
namespace xe {
namespace gpu {
namespace vulkan {
class VulkanGraphicsSystem : public GraphicsSystem {
public:
VulkanGraphicsSystem();
~VulkanGraphicsSystem() override;
X_STATUS Setup(cpu::Processor* processor, kernel::KernelState* kernel_state,
ui::Window* target_window) override;
void Shutdown() override;
private:
std::unique_ptr<CommandProcessor> CreateCommandProcessor() override;
void Swap(xe::ui::UIEvent* e) override;
xe::ui::vulkan::VulkanContext* display_context_ = nullptr;
};
} // namespace vulkan
} // namespace gpu
} // namespace xe
#endif // XENIA_GPU_VULKAN_VULKAN_GRAPHICS_SYSTEM_H_

View File

@@ -0,0 +1,56 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2016 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "xenia/gpu/vulkan/vulkan_shader.h"
#include "xenia/base/assert.h"
#include "xenia/base/logging.h"
#include "xenia/base/math.h"
#include "xenia/ui/vulkan/vulkan_util.h"
namespace xe {
namespace gpu {
namespace vulkan {
using xe::ui::vulkan::CheckResult;
VulkanShader::VulkanShader(VkDevice device, ShaderType shader_type,
uint64_t data_hash, const uint32_t* dword_ptr,
uint32_t dword_count)
: Shader(shader_type, data_hash, dword_ptr, dword_count), device_(device) {}
VulkanShader::~VulkanShader() {
if (shader_module_) {
vkDestroyShaderModule(device_, shader_module_, nullptr);
shader_module_ = nullptr;
}
}
bool VulkanShader::Prepare() {
assert_null(shader_module_);
assert_true(is_valid());
// Create the shader module.
VkShaderModuleCreateInfo shader_info;
shader_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
shader_info.pNext = nullptr;
shader_info.flags = 0;
shader_info.codeSize = translated_binary_.size();
shader_info.pCode =
reinterpret_cast<const uint32_t*>(translated_binary_.data());
auto status =
vkCreateShaderModule(device_, &shader_info, nullptr, &shader_module_);
CheckResult(status, "vkCreateShaderModule");
return status == VK_SUCCESS;
}
} // namespace vulkan
} // namespace gpu
} // namespace xe

View File

@@ -0,0 +1,42 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2016 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_GPU_VULKAN_VULKAN_SHADER_H_
#define XENIA_GPU_VULKAN_VULKAN_SHADER_H_
#include <string>
#include "xenia/gpu/shader.h"
#include "xenia/ui/vulkan/vulkan_context.h"
namespace xe {
namespace gpu {
namespace vulkan {
class VulkanShader : public Shader {
public:
VulkanShader(VkDevice device, ShaderType shader_type, uint64_t data_hash,
const uint32_t* dword_ptr, uint32_t dword_count);
~VulkanShader() override;
// Available only if the shader is_valid and has been prepared.
VkShaderModule shader_module() const { return shader_module_; }
bool Prepare();
private:
VkDevice device_ = nullptr;
VkShaderModule shader_module_ = nullptr;
};
} // namespace vulkan
} // namespace gpu
} // namespace xe
#endif // XENIA_GPU_VULKAN_VULKAN_SHADER_H_

View File

@@ -0,0 +1,76 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2016 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "xenia/base/logging.h"
#include "xenia/base/main.h"
#include "xenia/gpu/trace_dump.h"
#include "xenia/gpu/vulkan/vulkan_command_processor.h"
#include "xenia/gpu/vulkan/vulkan_graphics_system.h"
namespace xe {
namespace gpu {
namespace vulkan {
using namespace xe::gpu::xenos;
class VulkanTraceDump : public TraceDump {
public:
std::unique_ptr<gpu::GraphicsSystem> CreateGraphicsSystem() override {
return std::unique_ptr<gpu::GraphicsSystem>(new VulkanGraphicsSystem());
}
uintptr_t GetColorRenderTarget(uint32_t pitch, MsaaSamples samples,
uint32_t base,
ColorRenderTargetFormat format) override {
auto command_processor = static_cast<VulkanCommandProcessor*>(
graphics_system_->command_processor());
// return command_processor->GetColorRenderTarget(pitch, samples, base,
// format);
return 0;
}
uintptr_t GetDepthRenderTarget(uint32_t pitch, MsaaSamples samples,
uint32_t base,
DepthRenderTargetFormat format) override {
auto command_processor = static_cast<VulkanCommandProcessor*>(
graphics_system_->command_processor());
// return command_processor->GetDepthRenderTarget(pitch, samples, base,
// format);
return 0;
}
uintptr_t GetTextureEntry(const TextureInfo& texture_info,
const SamplerInfo& sampler_info) override {
auto command_processor = static_cast<VulkanCommandProcessor*>(
graphics_system_->command_processor());
// auto entry_view =
// command_processor->texture_cache()->Demand(texture_info,
// sampler_info);
// if (!entry_view) {
// return 0;
//}
// auto texture = entry_view->texture;
// return static_cast<uintptr_t>(texture->handle);
return 0;
}
};
int trace_dump_main(const std::vector<std::wstring>& args) {
VulkanTraceDump trace_dump;
return trace_dump.Main(args);
}
} // namespace vulkan
} // namespace gpu
} // namespace xe
DEFINE_ENTRY_POINT(L"xenia-gpu-vulkan-trace-dump",
L"xenia-gpu-vulkan-trace-dump some.trace",
xe::gpu::vulkan::trace_dump_main);

View File

@@ -0,0 +1,76 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2016 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "xenia/base/logging.h"
#include "xenia/base/main.h"
#include "xenia/gpu/trace_viewer.h"
#include "xenia/gpu/vulkan/vulkan_command_processor.h"
#include "xenia/gpu/vulkan/vulkan_graphics_system.h"
namespace xe {
namespace gpu {
namespace vulkan {
using namespace xe::gpu::xenos;
class VulkanTraceViewer : public TraceViewer {
public:
std::unique_ptr<gpu::GraphicsSystem> CreateGraphicsSystem() override {
return std::unique_ptr<gpu::GraphicsSystem>(new VulkanGraphicsSystem());
}
uintptr_t GetColorRenderTarget(uint32_t pitch, MsaaSamples samples,
uint32_t base,
ColorRenderTargetFormat format) override {
auto command_processor = static_cast<VulkanCommandProcessor*>(
graphics_system_->command_processor());
// return command_processor->GetColorRenderTarget(pitch, samples, base,
// format);
return 0;
}
uintptr_t GetDepthRenderTarget(uint32_t pitch, MsaaSamples samples,
uint32_t base,
DepthRenderTargetFormat format) override {
auto command_processor = static_cast<VulkanCommandProcessor*>(
graphics_system_->command_processor());
// return command_processor->GetDepthRenderTarget(pitch, samples, base,
// format);
return 0;
}
uintptr_t GetTextureEntry(const TextureInfo& texture_info,
const SamplerInfo& sampler_info) override {
auto command_processor = static_cast<VulkanCommandProcessor*>(
graphics_system_->command_processor());
// auto entry_view =
// command_processor->texture_cache()->Demand(texture_info,
// sampler_info);
// if (!entry_view) {
// return 0;
//}
// auto texture = entry_view->texture;
// return static_cast<uintptr_t>(texture->handle);
return 0;
}
};
int trace_viewer_main(const std::vector<std::wstring>& args) {
VulkanTraceViewer trace_viewer;
return trace_viewer.Main(args);
}
} // namespace vulkan
} // namespace gpu
} // namespace xe
DEFINE_ENTRY_POINT(L"xenia-gpu-vulkan-trace-viewer",
L"xenia-gpu-vulkan-trace-viewer some.trace",
xe::gpu::vulkan::trace_viewer_main);

View File

@@ -49,6 +49,7 @@ enum class PrimitiveType : uint32_t {
kLineLoop = 0x0C,
kQuadList = 0x0D,
kQuadStrip = 0x0E,
kUnknown0x11 = 0x11,
};
enum class Dimension : uint32_t {
@@ -382,7 +383,7 @@ XEPACKEDUNION(xe_gpu_vertex_fetch_t, {
uint32_t type : 2;
uint32_t address : 30;
uint32_t endian : 2;
uint32_t size : 24;
uint32_t size : 24; // size in words
uint32_t unk1 : 6;
});
XEPACKEDSTRUCTANONYMOUS({
@@ -486,6 +487,46 @@ XEPACKEDUNION(xe_gpu_fetch_group_t, {
});
});
enum Event {
SAMPLE_STREAMOUTSTATS1 = (1 << 0),
SAMPLE_STREAMOUTSTATS2 = (2 << 0),
SAMPLE_STREAMOUTSTATS3 = (3 << 0),
CACHE_FLUSH_TS = (4 << 0),
CACHE_FLUSH = (6 << 0),
CS_PARTIAL_FLUSH = (7 << 0),
VGT_STREAMOUT_RESET = (10 << 0),
END_OF_PIPE_INCR_DE = (11 << 0),
END_OF_PIPE_IB_END = (12 << 0),
RST_PIX_CNT = (13 << 0),
VS_PARTIAL_FLUSH = (15 << 0),
PS_PARTIAL_FLUSH = (16 << 0),
CACHE_FLUSH_AND_INV_TS_EVENT = (20 << 0),
ZPASS_DONE = (21 << 0),
CACHE_FLUSH_AND_INV_EVENT = (22 << 0),
PERFCOUNTER_START = (23 << 0),
PERFCOUNTER_STOP = (24 << 0),
PIPELINESTAT_START = (25 << 0),
PIPELINESTAT_STOP = (26 << 0),
PERFCOUNTER_SAMPLE = (27 << 0),
SAMPLE_PIPELINESTAT = (30 << 0),
SAMPLE_STREAMOUTSTATS = (32 << 0),
RESET_VTX_CNT = (33 << 0),
VGT_FLUSH = (36 << 0),
BOTTOM_OF_PIPE_TS = (40 << 0),
DB_CACHE_FLUSH_AND_INV = (42 << 0),
FLUSH_AND_INV_DB_DATA_TS = (43 << 0),
FLUSH_AND_INV_DB_META = (44 << 0),
FLUSH_AND_INV_CB_DATA_TS = (45 << 0),
FLUSH_AND_INV_CB_META = (46 << 0),
CS_DONE = (47 << 0),
PS_DONE = (48 << 0),
FLUSH_AND_INV_CB_PIXEL_DATA = (49 << 0),
THREAD_TRACE_START = (51 << 0),
THREAD_TRACE_STOP = (52 << 0),
THREAD_TRACE_FLUSH = (54 << 0),
THREAD_TRACE_FINISH = (55 << 0),
};
// Opcodes (IT_OPCODE) for Type-3 commands in the ringbuffer.
// https://github.com/freedreno/amd-gpu/blob/master/include/api/gsl_pm4types.h
// Not sure if all of these are used.
@@ -501,7 +542,7 @@ enum Type3Opcode {
PM4_WAIT_FOR_IDLE = 0x26, // wait for the IDLE state of the engine
PM4_WAIT_REG_MEM = 0x3c, // wait until a register or memory location is a specific value
PM4_WAIT_REG_EQ = 0x52, // wait until a register location is equal to a specific value
PM4_WAT_REG_GTE = 0x53, // wait until a register location is >= a specific value
PM4_WAIT_REG_GTE = 0x53, // wait until a register location is >= a specific value
PM4_WAIT_UNTIL_READ = 0x5c, // wait until a read completes
PM4_WAIT_IB_PFD_COMPLETE = 0x5d, // wait until all base/size writes from an IB_PFD packet have completed