Better vertex buffer construction, supporting packed data.

This commit is contained in:
Ben Vanik 2014-01-18 00:12:57 -08:00
parent ba9d343c51
commit 99c72f24f2
5 changed files with 241 additions and 164 deletions

View File

@ -139,9 +139,12 @@ int D3D11GraphicsDriver::SetupDraw(XE_GPU_PRIMITIVE_TYPE prim_type) {
case XE_GPU_PRIMITIVE_TYPE_TRIANGLE_STRIP: case XE_GPU_PRIMITIVE_TYPE_TRIANGLE_STRIP:
primitive_topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; primitive_topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
break; break;
case XE_GPU_PRIMITIVE_TYPE_RECTANGLE_LIST:
XELOGW("D3D11: faking RECTANGLE_LIST as a tri list");
primitive_topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
break;
case XE_GPU_PRIMITIVE_TYPE_TRIANGLE_FAN: case XE_GPU_PRIMITIVE_TYPE_TRIANGLE_FAN:
case XE_GPU_PRIMITIVE_TYPE_UNKNOWN_07: case XE_GPU_PRIMITIVE_TYPE_UNKNOWN_07:
case XE_GPU_PRIMITIVE_TYPE_RECTANGLE_LIST:
case XE_GPU_PRIMITIVE_TYPE_LINE_LOOP: case XE_GPU_PRIMITIVE_TYPE_LINE_LOOP:
XELOGE("D3D11: unsupported primitive type %d", prim_type); XELOGE("D3D11: unsupported primitive type %d", prim_type);
return 1; return 1;
@ -429,6 +432,17 @@ int D3D11GraphicsDriver::BindShaders() {
} }
int D3D11GraphicsDriver::PrepareFetchers() { int D3D11GraphicsDriver::PrepareFetchers() {
XEASSERTNOTNULL(state_.vertex_shader);
auto inputs = state_.vertex_shader->GetVertexBufferInputs();
for (size_t n = 0; n < inputs->count; n++) {
auto input = inputs->descs[n];
if (PrepareVertexBuffer(input)) {
XELOGE("D3D11: unable to prepare vertex buffer");
return 1;
}
}
// TODO(benvanik): rewrite by sampler
RegisterFile& rf = register_file_; RegisterFile& rf = register_file_;
for (int n = 0; n < 32; n++) { for (int n = 0; n < 32; n++) {
int r = XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0 + n * 6; int r = XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0 + n * 6;
@ -437,38 +451,37 @@ int D3D11GraphicsDriver::PrepareFetchers() {
if (PrepareTextureFetcher(n, &group->texture_fetch)) { if (PrepareTextureFetcher(n, &group->texture_fetch)) {
return 1; return 1;
} }
} else {
// TODO(benvanik): verify register numbering.
if (group->type_0 == 0x3) {
if (PrepareVertexFetcher(n * 3 + 0, &group->vertex_fetch_0)) {
return 1;
}
}
if (group->type_1 == 0x3) {
if (PrepareVertexFetcher(n * 3 + 1, &group->vertex_fetch_1)) {
return 1;
}
}
if (group->type_2 == 0x3) {
if (PrepareVertexFetcher(n * 3 + 2, &group->vertex_fetch_2)) {
return 1;
}
}
} }
} }
return 0; return 0;
} }
int D3D11GraphicsDriver::PrepareVertexFetcher( int D3D11GraphicsDriver::PrepareVertexBuffer(Shader::vtx_buffer_desc_t& desc) {
int fetch_slot, xe_gpu_vertex_fetch_t* fetch) { RegisterFile& rf = register_file_;
uint32_t address = (fetch->address << 2) + address_translation_; int r = XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0 + (desc.fetch_slot / 3) * 6;
uint32_t size_dwords = fetch->size; xe_gpu_fetch_group_t* group = (xe_gpu_fetch_group_t*)&rf.values[r];
xe_gpu_vertex_fetch_t* fetch = NULL;
switch (desc.fetch_slot % 3) {
case 0:
fetch = &group->vertex_fetch_0;
break;
case 1:
fetch = &group->vertex_fetch_1;
break;
case 2:
fetch = &group->vertex_fetch_2;
break;
}
XEASSERTNOTNULL(fetch);
// If this assert doesn't hold, maybe we just abort?
XEASSERT(fetch->type == 0x3);
XEASSERTNOTZERO(fetch->size);
ID3D11Buffer* buffer = 0; ID3D11Buffer* buffer = 0;
D3D11_BUFFER_DESC buffer_desc; D3D11_BUFFER_DESC buffer_desc;
xe_zero_struct(&buffer_desc, sizeof(buffer_desc)); xe_zero_struct(&buffer_desc, sizeof(buffer_desc));
buffer_desc.ByteWidth = size_dwords * 4; buffer_desc.ByteWidth = fetch->size * 4;
buffer_desc.Usage = D3D11_USAGE_DYNAMIC; buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
buffer_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER; buffer_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
@ -484,15 +497,23 @@ int D3D11GraphicsDriver::PrepareVertexFetcher(
XESAFERELEASE(buffer); XESAFERELEASE(buffer);
return 1; return 1;
} }
uint32_t* src = (uint32_t*)memory_->Translate(address); uint32_t address = (fetch->address << 2) + address_translation_;
uint32_t* dest = (uint32_t*)res.pData; uint8_t* src = (uint8_t*)memory_->Translate(address);
for (uint32_t n = 0; n < size_dwords; n++) { uint8_t* dest = (uint8_t*)res.pData;
// union { // TODO(benvanik): rewrite to be faster/special case common/etc
// uint32_t i; for (size_t n = 0; n < desc.element_count; n++) {
// float f; auto& el = desc.elements[n];
// } d = {XESWAP32(src[n])}; uint32_t stride = desc.stride_words;
// XELOGGPU("v%.3d %0.8X %g", n, d.i, d.f); uint32_t count = fetch->size / stride;
dest[n] = XESWAP32(src[n]); uint32_t* src_ptr = (uint32_t*)(src + el.offset_words * 4);
uint32_t* dest_ptr = (uint32_t*)(dest + el.offset_words * 4);
uint32_t o = 0;
for (uint32_t i = 0; i < count; i++) {
for (uint32_t j = 0; j < el.size_words; j++) {
dest_ptr[o + j] = XESWAP32(src_ptr[o + j]);
}
o += stride;
}
} }
context_->Unmap(buffer, 0); context_->Unmap(buffer, 0);
@ -500,14 +521,10 @@ int D3D11GraphicsDriver::PrepareVertexFetcher(
if (!vs) { if (!vs) {
return 1; return 1;
} }
const instr_fetch_vtx_t* vtx = vs->GetFetchVtxBySlot(fetch_slot);
if (!vtx->must_be_one) {
return 1;
}
// TODO(benvanik): always dword aligned? // TODO(benvanik): always dword aligned?
uint32_t stride = vtx->stride * 4; uint32_t stride = desc.stride_words * 4;
uint32_t offset = 0; uint32_t offset = 0;
int vb_slot = 95 - fetch_slot; int vb_slot = desc.input_index;
context_->IASetVertexBuffers(vb_slot, 1, &buffer, &stride, &offset); context_->IASetVertexBuffers(vb_slot, 1, &buffer, &stride, &offset);
buffer->Release(); buffer->Release();

View File

@ -13,6 +13,7 @@
#include <xenia/core.h> #include <xenia/core.h>
#include <xenia/gpu/graphics_driver.h> #include <xenia/gpu/graphics_driver.h>
#include <xenia/gpu/shader.h>
#include <xenia/gpu/d3d11/d3d11_gpu-private.h> #include <xenia/gpu/d3d11/d3d11_gpu-private.h>
#include <xenia/gpu/xenos/xenos.h> #include <xenia/gpu/xenos/xenos.h>
@ -56,8 +57,7 @@ private:
int UpdateConstantBuffers(); int UpdateConstantBuffers();
int BindShaders(); int BindShaders();
int PrepareFetchers(); int PrepareFetchers();
int PrepareVertexFetcher( int PrepareVertexBuffer(Shader::vtx_buffer_desc_t& desc);
int fetch_slot, xenos::xe_gpu_vertex_fetch_t* fetch);
int PrepareTextureFetcher( int PrepareTextureFetcher(
int fetch_slot, xenos::xe_gpu_texture_fetch_t* fetch); int fetch_slot, xenos::xe_gpu_texture_fetch_t* fetch);
int PrepareIndexBuffer( int PrepareIndexBuffer(

View File

@ -184,119 +184,101 @@ int D3D11VertexShader::Prepare(xe_gpu_program_cntl_t* program_cntl) {
} }
// Create input layout. // Create input layout.
size_t element_count = fetch_vtxs_.size(); size_t element_count = 0;
for (uint32_t n = 0; n < vtx_buffer_inputs_.count; n++) {
element_count += vtx_buffer_inputs_.descs[n].element_count;
}
D3D11_INPUT_ELEMENT_DESC* element_descs = D3D11_INPUT_ELEMENT_DESC* element_descs =
(D3D11_INPUT_ELEMENT_DESC*)xe_alloca( (D3D11_INPUT_ELEMENT_DESC*)xe_alloca(
sizeof(D3D11_INPUT_ELEMENT_DESC) * element_count); sizeof(D3D11_INPUT_ELEMENT_DESC) * element_count);
int n = 0; uint32_t el_index = 0;
for (std::vector<instr_fetch_vtx_t>::iterator it = fetch_vtxs_.begin(); for (uint32_t n = 0; n < vtx_buffer_inputs_.count; n++) {
it != fetch_vtxs_.end(); ++it, ++n) { auto& input = vtx_buffer_inputs_.descs[n];
const instr_fetch_vtx_t& vtx = *it; for (uint32_t m = 0; m < input.element_count; m++) {
DXGI_FORMAT vtx_format; auto& el = input.elements[m];
switch (vtx.format) { uint32_t vb_slot = input.input_index;
case FMT_1_REVERSE: uint32_t num_format_all = el.vtx_fetch.num_format_all;
vtx_format = DXGI_FORMAT_R1_UNORM; // ? uint32_t format_comp_all = el.vtx_fetch.format_comp_all;
break; DXGI_FORMAT vtx_format;
case FMT_8: switch (el.format) {
if (!vtx.num_format_all) { case FMT_8_8_8_8:
vtx_format = vtx.format_comp_all ? if (!num_format_all) {
DXGI_FORMAT_R8_SNORM : DXGI_FORMAT_R8_UNORM; vtx_format = format_comp_all ?
} else { DXGI_FORMAT_R8G8B8A8_SNORM : DXGI_FORMAT_R8G8B8A8_UNORM;
vtx_format = vtx.format_comp_all ? } else {
DXGI_FORMAT_R8_SINT : DXGI_FORMAT_R8_UINT; vtx_format = format_comp_all ?
DXGI_FORMAT_R8G8B8A8_SINT : DXGI_FORMAT_R8G8B8A8_UINT;
}
break;
case FMT_2_10_10_10:
if (!num_format_all) {
vtx_format = DXGI_FORMAT_R10G10B10A2_UNORM;
} else {
vtx_format = DXGI_FORMAT_R10G10B10A2_UINT;
}
break;
// DXGI_FORMAT_R11G11B10_FLOAT?
case FMT_16_16:
if (!num_format_all) {
vtx_format = format_comp_all ?
DXGI_FORMAT_R16G16_SNORM : DXGI_FORMAT_R16G16_UNORM;
} else {
vtx_format = format_comp_all ?
DXGI_FORMAT_R16G16_SINT : DXGI_FORMAT_R16G16_UINT;
}
break;
case FMT_16_16_16_16:
if (!num_format_all) {
vtx_format = format_comp_all ?
DXGI_FORMAT_R16G16B16A16_SNORM : DXGI_FORMAT_R16G16B16A16_UNORM;
} else {
vtx_format = format_comp_all ?
DXGI_FORMAT_R16G16B16A16_SINT : DXGI_FORMAT_R16G16B16A16_UINT;
}
break;
case FMT_16_16_FLOAT:
vtx_format = DXGI_FORMAT_R16G16_FLOAT;
break;
case FMT_16_16_16_16_FLOAT:
vtx_format = DXGI_FORMAT_R16G16B16A16_FLOAT;
break;
case FMT_32:
vtx_format = format_comp_all ?
DXGI_FORMAT_R32_SINT : DXGI_FORMAT_R32_UINT;
break;
case FMT_32_32:
vtx_format = format_comp_all ?
DXGI_FORMAT_R32G32_SINT : DXGI_FORMAT_R32G32_UINT;
break;
case FMT_32_32_32_32:
vtx_format = format_comp_all ?
DXGI_FORMAT_R32G32B32A32_SINT : DXGI_FORMAT_R32G32B32A32_UINT;
break;
case FMT_32_FLOAT:
vtx_format = DXGI_FORMAT_R32_FLOAT;
break;
case FMT_32_32_FLOAT:
vtx_format = DXGI_FORMAT_R32G32_FLOAT;
break;
case FMT_32_32_32_FLOAT:
vtx_format = DXGI_FORMAT_R32G32B32_FLOAT;
break;
case FMT_32_32_32_32_FLOAT:
vtx_format = DXGI_FORMAT_R32G32B32A32_FLOAT;
break;
default:
XEASSERTALWAYS();
break;
} }
break; element_descs[el_index].SemanticName = "XE_VF";
case FMT_8_8_8_8: element_descs[el_index].SemanticIndex = el_index;
if (!vtx.num_format_all) { element_descs[el_index].Format = vtx_format;
vtx_format = vtx.format_comp_all ? element_descs[el_index].InputSlot = vb_slot;
DXGI_FORMAT_R8G8B8A8_SNORM : DXGI_FORMAT_R8G8B8A8_UNORM; element_descs[el_index].AlignedByteOffset = el.offset_words * 4;
} else { element_descs[el_index].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
vtx_format = vtx.format_comp_all ? element_descs[el_index].InstanceDataStepRate = 0;
DXGI_FORMAT_R8G8B8A8_SINT : DXGI_FORMAT_R8G8B8A8_UINT; el_index++;
}
break;
case FMT_2_10_10_10:
if (!vtx.num_format_all) {
vtx_format = DXGI_FORMAT_R10G10B10A2_UNORM;
} else {
vtx_format = DXGI_FORMAT_R10G10B10A2_UINT;
}
break;
case FMT_8_8:
if (!vtx.num_format_all) {
vtx_format = vtx.format_comp_all ?
DXGI_FORMAT_R8G8_SNORM : DXGI_FORMAT_R8G8_UNORM;
} else {
vtx_format = vtx.format_comp_all ?
DXGI_FORMAT_R8G8_SINT : DXGI_FORMAT_R8G8_UINT;
}
break;
case FMT_16:
if (!vtx.num_format_all) {
vtx_format = vtx.format_comp_all ?
DXGI_FORMAT_R16_SNORM : DXGI_FORMAT_R16_UNORM;
} else {
vtx_format = vtx.format_comp_all ?
DXGI_FORMAT_R16_SINT : DXGI_FORMAT_R16_UINT;
}
break;
case FMT_16_16:
if (!vtx.num_format_all) {
vtx_format = vtx.format_comp_all ?
DXGI_FORMAT_R16G16_SNORM : DXGI_FORMAT_R16G16_UNORM;
} else {
vtx_format = vtx.format_comp_all ?
DXGI_FORMAT_R16G16_SINT : DXGI_FORMAT_R16G16_UINT;
}
break;
case FMT_16_16_16_16:
if (!vtx.num_format_all) {
vtx_format = vtx.format_comp_all ?
DXGI_FORMAT_R16G16B16A16_SNORM : DXGI_FORMAT_R16G16B16A16_UNORM;
} else {
vtx_format = vtx.format_comp_all ?
DXGI_FORMAT_R16G16B16A16_SINT : DXGI_FORMAT_R16G16B16A16_UINT;
}
break;
case FMT_32:
vtx_format = vtx.format_comp_all ?
DXGI_FORMAT_R32_SINT : DXGI_FORMAT_R32_UINT;
break;
case FMT_32_32:
vtx_format = vtx.format_comp_all ?
DXGI_FORMAT_R32G32_SINT : DXGI_FORMAT_R32G32_UINT;
break;
case FMT_32_32_32_32:
vtx_format = vtx.format_comp_all ?
DXGI_FORMAT_R32G32B32A32_SINT : DXGI_FORMAT_R32G32B32A32_UINT;
break;
case FMT_32_FLOAT:
vtx_format = DXGI_FORMAT_R32_FLOAT;
break;
case FMT_32_32_FLOAT:
vtx_format = DXGI_FORMAT_R32G32_FLOAT;
break;
case FMT_32_32_32_32_FLOAT:
vtx_format = DXGI_FORMAT_R32G32B32A32_FLOAT;
break;
case FMT_32_32_32_FLOAT:
vtx_format = DXGI_FORMAT_R32G32B32_FLOAT;
break;
default:
XEASSERTALWAYS();
break;
} }
element_descs[n].SemanticName = "XE_VF";
element_descs[n].SemanticIndex = n;
element_descs[n].Format = vtx_format;
// Pick slot in same way that driver does.
// CONST(31, 2) = reg 31, index 2 = rf([31] * 6 + [2] * 2)
uint32_t fetch_slot = vtx.const_index * 3 + vtx.const_index_sel;
uint32_t vb_slot = 95 - fetch_slot;
element_descs[n].InputSlot = vb_slot;
element_descs[n].AlignedByteOffset = vtx.offset * 4;
element_descs[n].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
element_descs[n].InstanceDataStepRate = 0;
} }
hr = device_->CreateInputLayout( hr = device_->CreateInputLayout(
element_descs, element_descs,
@ -337,13 +319,17 @@ const char* D3D11VertexShader::Translate(xe_gpu_program_cntl_t* program_cntl) {
// Add vertex shader input. // Add vertex shader input.
output->append( output->append(
"struct VS_INPUT {\n"); "struct VS_INPUT {\n");
int n = 0; uint32_t el_index = 0;
for (std::vector<instr_fetch_vtx_t>::iterator it = fetch_vtxs_.begin(); for (uint32_t n = 0; n < vtx_buffer_inputs_.count; n++) {
it != fetch_vtxs_.end(); ++it, ++n) { auto& input = vtx_buffer_inputs_.descs[n];
const instr_fetch_vtx_t& vtx = *it; for (uint32_t m = 0; m < input.element_count; m++) {
uint32_t fetch_slot = vtx.const_index * 3 + vtx.const_index_sel; auto& el = input.elements[m];
output->append( auto& vtx = el.vtx_fetch;
" float4 vf%u_%d : XE_VF%u;\n", fetch_slot, vtx.offset, n); uint32_t fetch_slot = vtx.const_index * 3 + vtx.const_index_sel;
output->append(
" float4 vf%u_%d : XE_VF%u;\n", fetch_slot, vtx.offset, el_index);
el_index++;
}
} }
output->append( output->append(
"};\n"); "};\n");

View File

@ -23,7 +23,7 @@ Shader::Shader(
uint64_t hash) : uint64_t hash) :
type_(type), hash_(hash), is_prepared_(false), disasm_src_(NULL) { type_(type), hash_(hash), is_prepared_(false), disasm_src_(NULL) {
xe_zero_struct(&alloc_counts_, sizeof(alloc_counts_)); xe_zero_struct(&alloc_counts_, sizeof(alloc_counts_));
xe_zero_struct(fetch_vtx_slots_, sizeof(fetch_vtx_slots_)); xe_zero_struct(&vtx_buffer_inputs_, sizeof(vtx_buffer_inputs_));
// Verify. // Verify.
dword_count_ = length / 4; dword_count_ = length / 4;
@ -146,14 +146,72 @@ void Shader::GatherVertexFetch(const instr_fetch_vtx_t* vtx) {
// num_format_all ? integer : fraction // num_format_all ? integer : fraction
// exp_adjust_all - [-32,31] - (2^exp_adjust_all)*fetch - 0 = default // exp_adjust_all - [-32,31] - (2^exp_adjust_all)*fetch - 0 = default
fetch_vtxs_.push_back(*vtx);
uint32_t fetch_slot = vtx->const_index * 3 + vtx->const_index_sel; uint32_t fetch_slot = vtx->const_index * 3 + vtx->const_index_sel;
fetch_vtx_slots_[fetch_slot] = *vtx; auto& inputs = vtx_buffer_inputs_;
vtx_buffer_element_t* el = NULL;
for (size_t n = 0; n < inputs.count; n++) {
auto& input = inputs.descs[n];
if (input.fetch_slot == fetch_slot) {
XEASSERT(input.element_count + 1 < XECOUNT(input.elements));
// It may not hold that all strides are equal, but I hope it does.
XEASSERT(!vtx->stride || input.stride_words == vtx->stride);
el = &input.elements[input.element_count++];
break;
}
}
if (!el) {
XEASSERTNOTZERO(vtx->stride);
XEASSERT(inputs.count + 1 < XECOUNT(inputs.descs));
auto& input = inputs.descs[inputs.count++];
input.input_index = inputs.count - 1;
input.fetch_slot = fetch_slot;
input.stride_words = vtx->stride;
el = &input.elements[input.element_count++];
}
el->vtx_fetch = *vtx;
el->format = vtx->format;
el->offset_words = vtx->offset;
el->size_words = 0;
switch (el->format) {
case FMT_8_8_8_8:
case FMT_2_10_10_10:
case FMT_10_11_11:
case FMT_11_11_10:
el->size_words = 1;
break;
case FMT_16_16:
case FMT_16_16_FLOAT:
el->size_words = 1;
break;
case FMT_16_16_16_16:
case FMT_16_16_16_16_FLOAT:
el->size_words = 2;
break;
case FMT_32:
case FMT_32_FLOAT:
el->size_words = 1;
break;
case FMT_32_32:
case FMT_32_32_FLOAT:
el->size_words = 2;
break;
case FMT_32_32_32_FLOAT:
el->size_words = 3;
break;
case FMT_32_32_32_32:
case FMT_32_32_32_32_FLOAT:
el->size_words = 4;
break;
default:
XELOGE("Unknown vertex format: %d", el->format);
XEASSERTALWAYS();
break;
}
} }
const instr_fetch_vtx_t* Shader::GetFetchVtxBySlot(uint32_t fetch_slot) { const Shader::vtx_buffer_inputs_t* Shader::GetVertexBufferInputs() {
return &fetch_vtx_slots_[fetch_slot]; return &vtx_buffer_inputs_;
} }
void Shader::GatherTextureFetch(const xenos::instr_fetch_tex_t* tex) { void Shader::GatherTextureFetch(const xenos::instr_fetch_tex_t* tex) {

View File

@ -34,7 +34,24 @@ public:
const char* disasm_src() const { return disasm_src_; } const char* disasm_src() const { return disasm_src_; }
const xenos::instr_fetch_vtx_t* GetFetchVtxBySlot(uint32_t fetch_slot); typedef struct {
xenos::instr_fetch_vtx_t vtx_fetch;
uint32_t format;
uint32_t offset_words;
uint32_t size_words;
} vtx_buffer_element_t;
typedef struct {
uint32_t input_index;
uint32_t fetch_slot;
uint32_t stride_words;
uint32_t element_count;
vtx_buffer_element_t elements[16];
} vtx_buffer_desc_t;
typedef struct {
uint32_t count;
vtx_buffer_desc_t descs[16];
} vtx_buffer_inputs_t;
const vtx_buffer_inputs_t* GetVertexBufferInputs();
typedef struct { typedef struct {
uint32_t positions; uint32_t positions;
@ -62,8 +79,7 @@ protected:
alloc_counts_t alloc_counts_; alloc_counts_t alloc_counts_;
std::vector<xenos::instr_cf_exec_t> execs_; std::vector<xenos::instr_cf_exec_t> execs_;
std::vector<xenos::instr_cf_alloc_t> allocs_; std::vector<xenos::instr_cf_alloc_t> allocs_;
std::vector<xenos::instr_fetch_vtx_t> fetch_vtxs_; vtx_buffer_inputs_t vtx_buffer_inputs_;
xenos::instr_fetch_vtx_t fetch_vtx_slots_[96];
std::vector<xenos::instr_fetch_tex_t> fetch_texs_; std::vector<xenos::instr_fetch_tex_t> fetch_texs_;
}; };