mirror of https://github.com/xemu-project/xemu.git
nv2a/vk: Fixup unaligned attribute data in inline buffer
This commit is contained in:
parent
3096f2a9c8
commit
2f910eeacf
|
@ -1819,14 +1819,11 @@ static void pgraph_vk_debug_attrs(NV2AState *d)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void bind_vertex_buffer(PGRAPHState *pg, int buffer_idx,
|
static void bind_vertex_buffer(PGRAPHState *pg, uint16_t inline_map,
|
||||||
VkDeviceSize offset)
|
VkDeviceSize offset)
|
||||||
{
|
{
|
||||||
PGRAPHVkState *r = pg->vk_renderer_state;
|
PGRAPHVkState *r = pg->vk_renderer_state;
|
||||||
|
|
||||||
assert(buffer_idx == BUFFER_VERTEX_RAM ||
|
|
||||||
buffer_idx == BUFFER_VERTEX_INLINE);
|
|
||||||
|
|
||||||
if (r->num_active_vertex_binding_descriptions == 0) {
|
if (r->num_active_vertex_binding_descriptions == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1836,6 +1833,8 @@ static void bind_vertex_buffer(PGRAPHState *pg, int buffer_idx,
|
||||||
|
|
||||||
for (int i = 0; i < r->num_active_vertex_binding_descriptions; i++) {
|
for (int i = 0; i < r->num_active_vertex_binding_descriptions; i++) {
|
||||||
int attr_idx = r->vertex_attribute_descriptions[i].location;
|
int attr_idx = r->vertex_attribute_descriptions[i].location;
|
||||||
|
int buffer_idx = (inline_map & (1 << attr_idx)) ? BUFFER_VERTEX_INLINE :
|
||||||
|
BUFFER_VERTEX_RAM;
|
||||||
buffers[i] = r->storage_buffers[buffer_idx].buffer;
|
buffers[i] = r->storage_buffers[buffer_idx].buffer;
|
||||||
offsets[i] = offset + r->vertex_attribute_offsets[attr_idx];
|
offsets[i] = offset + r->vertex_attribute_offsets[attr_idx];
|
||||||
}
|
}
|
||||||
|
@ -1845,6 +1844,11 @@ static void bind_vertex_buffer(PGRAPHState *pg, int buffer_idx,
|
||||||
offsets);
|
offsets);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void bind_inline_vertex_buffer(PGRAPHState *pg, VkDeviceSize offset)
|
||||||
|
{
|
||||||
|
bind_vertex_buffer(pg, 0xffff, offset);
|
||||||
|
}
|
||||||
|
|
||||||
void pgraph_vk_set_surface_dirty(PGRAPHState *pg, bool color, bool zeta)
|
void pgraph_vk_set_surface_dirty(PGRAPHState *pg, bool color, bool zeta)
|
||||||
{
|
{
|
||||||
NV2A_DPRINTF("pgraph_set_surface_dirty(%d, %d) -- %d %d\n", color, zeta,
|
NV2A_DPRINTF("pgraph_set_surface_dirty(%d, %d) -- %d %d\n", color, zeta,
|
||||||
|
@ -1881,6 +1885,160 @@ static bool ensure_buffer_space(PGRAPHState *pg, int index, VkDeviceSize size)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void get_size_and_count_for_format(VkFormat fmt, size_t *size, size_t *count)
|
||||||
|
{
|
||||||
|
static const struct {
|
||||||
|
size_t size;
|
||||||
|
size_t count;
|
||||||
|
} table[] = {
|
||||||
|
[VK_FORMAT_R8_UNORM] = { 1, 1 },
|
||||||
|
[VK_FORMAT_R8G8_UNORM] = { 1, 2 },
|
||||||
|
[VK_FORMAT_R8G8B8_UNORM] = { 1, 3 },
|
||||||
|
[VK_FORMAT_R8G8B8A8_UNORM] = { 1, 4 },
|
||||||
|
[VK_FORMAT_R16_SNORM] = { 2, 1 },
|
||||||
|
[VK_FORMAT_R16G16_SNORM] = { 2, 2 },
|
||||||
|
[VK_FORMAT_R16G16B16_SNORM] = { 2, 3 },
|
||||||
|
[VK_FORMAT_R16G16B16A16_SNORM] = { 2, 4 },
|
||||||
|
[VK_FORMAT_R16_SSCALED] = { 2, 1 },
|
||||||
|
[VK_FORMAT_R16G16_SSCALED] = { 2, 2 },
|
||||||
|
[VK_FORMAT_R16G16B16_SSCALED] = { 2, 3 },
|
||||||
|
[VK_FORMAT_R16G16B16A16_SSCALED] = { 2, 4 },
|
||||||
|
[VK_FORMAT_R32_SFLOAT] = { 4, 1 },
|
||||||
|
[VK_FORMAT_R32G32_SFLOAT] = { 4, 2 },
|
||||||
|
[VK_FORMAT_R32G32B32_SFLOAT] = { 4, 3 },
|
||||||
|
[VK_FORMAT_R32G32B32A32_SFLOAT] = { 4, 4 },
|
||||||
|
[VK_FORMAT_R32_SINT] = { 4, 1 },
|
||||||
|
};
|
||||||
|
|
||||||
|
assert(fmt < ARRAY_SIZE(table));
|
||||||
|
assert(table[fmt].size);
|
||||||
|
|
||||||
|
*size = table[fmt].size;
|
||||||
|
*count = table[fmt].count;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct VertexBufferRemap {
|
||||||
|
uint16_t attributes;
|
||||||
|
size_t buffer_space_required;
|
||||||
|
struct {
|
||||||
|
VkDeviceAddress offset;
|
||||||
|
VkDeviceSize stride;
|
||||||
|
} map[NV2A_VERTEXSHADER_ATTRIBUTES];
|
||||||
|
} VertexBufferRemap;
|
||||||
|
|
||||||
|
static VertexBufferRemap remap_unaligned_attributes(PGRAPHState *pg,
|
||||||
|
uint32_t num_vertices)
|
||||||
|
{
|
||||||
|
PGRAPHVkState *r = pg->vk_renderer_state;
|
||||||
|
|
||||||
|
VertexBufferRemap remap = {0};
|
||||||
|
|
||||||
|
VkDeviceAddress output_offset = 0;
|
||||||
|
|
||||||
|
for (int attr_id = 0; attr_id < NV2A_VERTEXSHADER_ATTRIBUTES; attr_id++) {
|
||||||
|
int desc_loc = r->vertex_attribute_to_description_location[attr_id];
|
||||||
|
if (desc_loc < 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkVertexInputBindingDescription *desc =
|
||||||
|
&r->vertex_binding_descriptions[desc_loc];
|
||||||
|
VkVertexInputAttributeDescription *attr =
|
||||||
|
&r->vertex_attribute_descriptions[desc_loc];
|
||||||
|
|
||||||
|
size_t element_size, element_count;
|
||||||
|
get_size_and_count_for_format(attr->format, &element_size, &element_count);
|
||||||
|
|
||||||
|
bool offset_valid =
|
||||||
|
(r->vertex_attribute_offsets[attr_id] % element_size == 0);
|
||||||
|
bool stride_valid = (desc->stride % element_size == 0);
|
||||||
|
|
||||||
|
if (offset_valid && stride_valid) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
remap.attributes |= 1 << attr_id;
|
||||||
|
remap.map[attr_id].offset = ROUND_UP(output_offset, element_size);
|
||||||
|
remap.map[attr_id].stride = element_size * element_count;
|
||||||
|
|
||||||
|
// fprintf(stderr,
|
||||||
|
// "attr %02d remapped: "
|
||||||
|
// "%08" HWADDR_PRIx "->%08" HWADDR_PRIx " "
|
||||||
|
// "stride=%d->%zd\n",
|
||||||
|
// attr_id, r->vertex_attribute_offsets[attr_id],
|
||||||
|
// remap.map[attr_id].offset, desc->stride,
|
||||||
|
// remap.map[attr_id].stride);
|
||||||
|
|
||||||
|
output_offset =
|
||||||
|
remap.map[attr_id].offset + remap.map[attr_id].stride * num_vertices;
|
||||||
|
}
|
||||||
|
|
||||||
|
remap.buffer_space_required = output_offset;
|
||||||
|
return remap;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void copy_remapped_attributes_to_inline_buffer(PGRAPHState *pg,
|
||||||
|
VertexBufferRemap remap,
|
||||||
|
uint32_t start_vertex,
|
||||||
|
uint32_t num_vertices)
|
||||||
|
{
|
||||||
|
NV2AState *d = container_of(pg, NV2AState, pgraph);
|
||||||
|
PGRAPHVkState *r = pg->vk_renderer_state;
|
||||||
|
StorageBuffer *buffer = &r->storage_buffers[BUFFER_VERTEX_INLINE_STAGING];
|
||||||
|
|
||||||
|
r->vertex_buffer_inline = remap.attributes;
|
||||||
|
|
||||||
|
if (!remap.attributes) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDeviceSize starting_offset = ROUND_UP(buffer->buffer_offset, 16);
|
||||||
|
size_t total_space_required =
|
||||||
|
(starting_offset - buffer->buffer_offset) + remap.buffer_space_required;
|
||||||
|
ensure_buffer_space(pg, BUFFER_VERTEX_INLINE_STAGING, total_space_required);
|
||||||
|
assert(pgraph_vk_buffer_has_space_for(pg, BUFFER_VERTEX_INLINE_STAGING,
|
||||||
|
total_space_required, 1));
|
||||||
|
|
||||||
|
buffer->buffer_offset = starting_offset; // Aligned
|
||||||
|
|
||||||
|
// FIXME: SIMD memcpy
|
||||||
|
// FIXME: Caching
|
||||||
|
// FIXME: Account for only what is drawn
|
||||||
|
assert(start_vertex == 0);
|
||||||
|
assert(buffer->mapped);
|
||||||
|
|
||||||
|
// Copy vertex data
|
||||||
|
for (int attr_id = 0; attr_id < NV2A_VERTEXSHADER_ATTRIBUTES; attr_id++) {
|
||||||
|
if (!(remap.attributes & (1 << attr_id))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bind_desc_loc =
|
||||||
|
r->vertex_attribute_to_description_location[attr_id];
|
||||||
|
assert(bind_desc_loc >= 0);
|
||||||
|
|
||||||
|
VkVertexInputBindingDescription *bind_desc =
|
||||||
|
&r->vertex_binding_descriptions[bind_desc_loc];
|
||||||
|
|
||||||
|
VkDeviceSize attr_buffer_offset =
|
||||||
|
buffer->buffer_offset + remap.map[attr_id].offset;
|
||||||
|
|
||||||
|
uint8_t *out_ptr = buffer->mapped + attr_buffer_offset;
|
||||||
|
uint8_t *in_ptr = d->vram_ptr + r->vertex_attribute_offsets[attr_id];
|
||||||
|
|
||||||
|
for (int vertex_id = 0; vertex_id < num_vertices; vertex_id++) {
|
||||||
|
memcpy(out_ptr, in_ptr, remap.map[attr_id].stride);
|
||||||
|
out_ptr += remap.map[attr_id].stride;
|
||||||
|
in_ptr += bind_desc->stride;
|
||||||
|
}
|
||||||
|
|
||||||
|
r->vertex_attribute_offsets[attr_id] = attr_buffer_offset;
|
||||||
|
bind_desc->stride = remap.map[attr_id].stride;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer->buffer_offset += remap.buffer_space_required;
|
||||||
|
}
|
||||||
|
|
||||||
void pgraph_vk_flush_draw(NV2AState *d)
|
void pgraph_vk_flush_draw(NV2AState *d)
|
||||||
{
|
{
|
||||||
PGRAPHState *pg = &d->pgraph;
|
PGRAPHState *pg = &d->pgraph;
|
||||||
|
@ -1904,11 +2062,19 @@ void pgraph_vk_flush_draw(NV2AState *d)
|
||||||
pgraph_vk_bind_vertex_attributes(d, pg->draw_arrays_min_start,
|
pgraph_vk_bind_vertex_attributes(d, pg->draw_arrays_min_start,
|
||||||
pg->draw_arrays_max_count - 1, false,
|
pg->draw_arrays_max_count - 1, false,
|
||||||
0, pg->draw_arrays_max_count - 1);
|
0, pg->draw_arrays_max_count - 1);
|
||||||
|
uint32_t min_element = INT_MAX;
|
||||||
|
uint32_t max_element = 0;
|
||||||
|
for (int i = 0; i < pg->draw_arrays_length; i++) {
|
||||||
|
min_element = MIN(pg->draw_arrays_start[i], min_element);
|
||||||
|
max_element = MAX(max_element, pg->draw_arrays_start[i] + pg->draw_arrays_count[i]);
|
||||||
|
}
|
||||||
sync_vertex_ram_buffer(pg);
|
sync_vertex_ram_buffer(pg);
|
||||||
|
VertexBufferRemap remap = remap_unaligned_attributes(pg, max_element);
|
||||||
|
copy_remapped_attributes_to_inline_buffer(pg, remap, 0, max_element);
|
||||||
|
|
||||||
begin_pre_draw(pg);
|
begin_pre_draw(pg);
|
||||||
begin_draw(pg);
|
begin_draw(pg);
|
||||||
bind_vertex_buffer(pg, BUFFER_VERTEX_RAM, 0);
|
bind_vertex_buffer(pg, remap.attributes, 0);
|
||||||
for (int i = 0; i < pg->draw_arrays_length; i++) {
|
for (int i = 0; i < pg->draw_arrays_length; i++) {
|
||||||
uint32_t start = pg->draw_arrays_start[i],
|
uint32_t start = pg->draw_arrays_start[i],
|
||||||
count = pg->draw_arrays_count[i];
|
count = pg->draw_arrays_count[i];
|
||||||
|
@ -1940,12 +2106,14 @@ void pgraph_vk_flush_draw(NV2AState *d)
|
||||||
d, min_element, max_element, false, 0,
|
d, min_element, max_element, false, 0,
|
||||||
pg->inline_elements[pg->inline_elements_length - 1]);
|
pg->inline_elements[pg->inline_elements_length - 1]);
|
||||||
sync_vertex_ram_buffer(pg);
|
sync_vertex_ram_buffer(pg);
|
||||||
|
VertexBufferRemap remap = remap_unaligned_attributes(pg, max_element + 1);
|
||||||
|
copy_remapped_attributes_to_inline_buffer(pg, remap, 0, max_element + 1);
|
||||||
|
|
||||||
begin_pre_draw(pg);
|
begin_pre_draw(pg);
|
||||||
VkDeviceSize buffer_offset = pgraph_vk_update_index_buffer(
|
VkDeviceSize buffer_offset = pgraph_vk_update_index_buffer(
|
||||||
pg, pg->inline_elements, index_data_size);
|
pg, pg->inline_elements, index_data_size);
|
||||||
begin_draw(pg);
|
begin_draw(pg);
|
||||||
bind_vertex_buffer(pg, BUFFER_VERTEX_RAM, 0);
|
bind_vertex_buffer(pg, remap.attributes, 0);
|
||||||
vkCmdBindIndexBuffer(r->command_buffer,
|
vkCmdBindIndexBuffer(r->command_buffer,
|
||||||
r->storage_buffers[BUFFER_INDEX].buffer,
|
r->storage_buffers[BUFFER_INDEX].buffer,
|
||||||
buffer_offset, VK_INDEX_TYPE_UINT32);
|
buffer_offset, VK_INDEX_TYPE_UINT32);
|
||||||
|
@ -1983,7 +2151,7 @@ void pgraph_vk_flush_draw(NV2AState *d)
|
||||||
VkDeviceSize buffer_offset = pgraph_vk_update_vertex_inline_buffer(
|
VkDeviceSize buffer_offset = pgraph_vk_update_vertex_inline_buffer(
|
||||||
pg, data, sizes, r->num_active_vertex_attribute_descriptions);
|
pg, data, sizes, r->num_active_vertex_attribute_descriptions);
|
||||||
begin_draw(pg);
|
begin_draw(pg);
|
||||||
bind_vertex_buffer(pg, BUFFER_VERTEX_INLINE, buffer_offset);
|
bind_inline_vertex_buffer(pg, buffer_offset);
|
||||||
vkCmdDraw(r->command_buffer, pg->inline_buffer_length, 1, 0, 0);
|
vkCmdDraw(r->command_buffer, pg->inline_buffer_length, 1, 0, 0);
|
||||||
end_draw(pg);
|
end_draw(pg);
|
||||||
|
|
||||||
|
@ -2024,7 +2192,7 @@ void pgraph_vk_flush_draw(NV2AState *d)
|
||||||
VkDeviceSize buffer_offset = pgraph_vk_update_vertex_inline_buffer(
|
VkDeviceSize buffer_offset = pgraph_vk_update_vertex_inline_buffer(
|
||||||
pg, &inline_array_data, &inline_array_data_size, 1);
|
pg, &inline_array_data, &inline_array_data_size, 1);
|
||||||
begin_draw(pg);
|
begin_draw(pg);
|
||||||
bind_vertex_buffer(pg, BUFFER_VERTEX_INLINE, buffer_offset);
|
bind_inline_vertex_buffer(pg, buffer_offset);
|
||||||
vkCmdDraw(r->command_buffer, index_count, 1, 0, 0);
|
vkCmdDraw(r->command_buffer, index_count, 1, 0, 0);
|
||||||
end_draw(pg);
|
end_draw(pg);
|
||||||
NV2A_VK_DGROUP_END();
|
NV2A_VK_DGROUP_END();
|
||||||
|
|
|
@ -343,6 +343,7 @@ typedef struct PGRAPHVkState {
|
||||||
VkVertexInputBindingDescription vertex_binding_descriptions[NV2A_VERTEXSHADER_ATTRIBUTES];
|
VkVertexInputBindingDescription vertex_binding_descriptions[NV2A_VERTEXSHADER_ATTRIBUTES];
|
||||||
int num_active_vertex_binding_descriptions;
|
int num_active_vertex_binding_descriptions;
|
||||||
hwaddr vertex_attribute_offsets[NV2A_VERTEXSHADER_ATTRIBUTES];
|
hwaddr vertex_attribute_offsets[NV2A_VERTEXSHADER_ATTRIBUTES];
|
||||||
|
uint16_t vertex_buffer_inline;
|
||||||
|
|
||||||
QTAILQ_HEAD(, SurfaceBinding) surfaces;
|
QTAILQ_HEAD(, SurfaceBinding) surfaces;
|
||||||
QTAILQ_HEAD(, SurfaceBinding) invalid_surfaces;
|
QTAILQ_HEAD(, SurfaceBinding) invalid_surfaces;
|
||||||
|
|
|
@ -263,7 +263,6 @@ void pgraph_vk_bind_vertex_attributes(NV2AState *d, unsigned int min_element,
|
||||||
};
|
};
|
||||||
|
|
||||||
r->vertex_attribute_offsets[i] = attrib_data_addr;
|
r->vertex_attribute_offsets[i] = attrib_data_addr;
|
||||||
// FIXME: Data alignment may not meet requirements
|
|
||||||
|
|
||||||
NV2A_VK_DGROUP_END();
|
NV2A_VK_DGROUP_END();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue