Fix for index buffer

- Fix index data offset in Vulkan geometry buffer.
- Normalize vertex colors.
- Add support for drawing from a given index offset.
This commit is contained in:
Attila Uygun 2023-10-10 00:04:46 +02:00
parent 2823aa3197
commit 14b2d22fbd
5 changed files with 53 additions and 28 deletions

View File

@ -26,6 +26,9 @@ constexpr GLenum kGlDataType[eng::kDataType_Max] = {
GL_UNSIGNED_BYTE, GL_FLOAT, GL_INT, GL_UNSIGNED_BYTE, GL_FLOAT, GL_INT,
GL_SHORT, GL_UNSIGNED_INT, GL_UNSIGNED_SHORT}; GL_SHORT, GL_UNSIGNED_INT, GL_UNSIGNED_SHORT};
constexpr GLboolean kGlNormalize[eng::kDataType_Max] = {
GL_TRUE, GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE};
const std::string kAttributeNames[eng::kAttribType_Max] = { const std::string kAttributeNames[eng::kAttribType_Max] = {
"in_color", "in_normal", "in_position", "in_tex_coord"}; "in_color", "in_normal", "in_position", "in_tex_coord"};
@ -132,11 +135,16 @@ void RendererOpenGL::DestroyGeometry(uint64_t resource_id) {
geometries_.erase(it); geometries_.erase(it);
} }
void RendererOpenGL::Draw(uint64_t resource_id) { void RendererOpenGL::Draw(uint64_t resource_id,
uint64_t num_indices,
uint64_t start_offset) {
auto it = geometries_.find(resource_id); auto it = geometries_.find(resource_id);
if (it == geometries_.end()) if (it == geometries_.end())
return; return;
if (num_indices == 0)
num_indices = it->second.num_indices;
// Set up the vertex data. // Set up the vertex data.
if (it->second.vertex_array_id) if (it->second.vertex_array_id)
glBindVertexArray(it->second.vertex_array_id); glBindVertexArray(it->second.vertex_array_id);
@ -152,14 +160,14 @@ void RendererOpenGL::Draw(uint64_t resource_id) {
(const GLvoid*)e.vertex_offset); (const GLvoid*)e.vertex_offset);
} }
if (it->second.num_indices > 0) if (num_indices > 0)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, it->second.index_buffer_id); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, it->second.index_buffer_id);
} }
// Draw the primitive. // Draw the primitive.
if (it->second.num_indices > 0) if (num_indices > 0)
glDrawElements(it->second.primitive, it->second.num_indices, glDrawElements(it->second.primitive, num_indices, it->second.index_type,
it->second.index_type, NULL); (void*)(intptr_t)(start_offset * sizeof(unsigned short)));
else else
glDrawArrays(it->second.primitive, 0, it->second.num_vertices); glDrawArrays(it->second.primitive, 0, it->second.num_vertices);
@ -446,7 +454,7 @@ bool RendererOpenGL::InitCommon() {
#if 0 #if 0
LOG(0) << " extensions:"; LOG(0) << " extensions:";
for (auto& ext : extensions) for (auto& ext : extensions)
LOG(0) << " " << ext.c_str()); LOG(0) << " " << ext.c_str();
#endif #endif
// Check for supported texture compression extensions. // Check for supported texture compression extensions.
@ -465,7 +473,8 @@ bool RendererOpenGL::InitCommon() {
extensions.find("GL_ATI_texture_compression_atitc") != extensions.end()) extensions.find("GL_ATI_texture_compression_atitc") != extensions.end())
texture_compression_.atc = true; texture_compression_.atc = true;
if (extensions.find("GL_OES_vertex_array_object") != extensions.end()) { if (extensions.find("GL_OES_vertex_array_object") != extensions.end() ||
extensions.find("GL_ARB_vertex_array_object") != extensions.end()) {
// This extension seems to be broken on older PowerVR drivers. // This extension seems to be broken on older PowerVR drivers.
if (!strstr(renderer, "PowerVR SGX 53") && if (!strstr(renderer, "PowerVR SGX 53") &&
!strstr(renderer, "PowerVR SGX 54") && !strstr(renderer, "PowerVR SGX 54") &&
@ -555,8 +564,9 @@ bool RendererOpenGL::SetupVertexLayout(
if (use_vao) { if (use_vao) {
// This will be saved into the vertex array object. // This will be saved into the vertex array object.
glEnableVertexAttribArray(attribute_index); glEnableVertexAttribArray(attribute_index);
glVertexAttribPointer(attribute_index, num_elements, type, GL_FALSE, glVertexAttribPointer(attribute_index, num_elements, type,
vertex_size, (const GLvoid*)vertex_offset); kGlNormalize[data_type], vertex_size,
(const GLvoid*)vertex_offset);
} else { } else {
// Need to keep this information for when rendering. // Need to keep this information for when rendering.
GeometryOpenGL::Element element; GeometryOpenGL::Element element;

View File

@ -33,7 +33,9 @@ class RendererOpenGL final : public Renderer {
uint64_t CreateGeometry(std::unique_ptr<Mesh> mesh) final; uint64_t CreateGeometry(std::unique_ptr<Mesh> mesh) final;
void DestroyGeometry(uint64_t resource_id) final; void DestroyGeometry(uint64_t resource_id) final;
void Draw(uint64_t resource_id) final; void Draw(uint64_t resource_id,
uint64_t num_indices = 0,
uint64_t start_offset = 0) final;
uint64_t CreateTexture() final; uint64_t CreateTexture() final;
void UpdateTexture(uint64_t resource_id, std::unique_ptr<Image> image) final; void UpdateTexture(uint64_t resource_id, std::unique_ptr<Image> image) final;

View File

@ -40,7 +40,9 @@ class Renderer {
virtual uint64_t CreateGeometry(std::unique_ptr<Mesh> mesh) = 0; virtual uint64_t CreateGeometry(std::unique_ptr<Mesh> mesh) = 0;
virtual void DestroyGeometry(uint64_t resource_id) = 0; virtual void DestroyGeometry(uint64_t resource_id) = 0;
virtual void Draw(uint64_t resource_id) = 0; virtual void Draw(uint64_t resource_id,
uint64_t num_indices = 0,
uint64_t start_offset = 0) = 0;
virtual uint64_t CreateTexture() = 0; virtual uint64_t CreateTexture() = 0;
virtual void UpdateTexture(uint64_t resource_id, virtual void UpdateTexture(uint64_t resource_id,

View File

@ -155,10 +155,10 @@ constexpr VkPrimitiveTopology kVkPrimitiveType[eng::kPrimitive_Max] = {
constexpr VkFormat kVkDataType[eng::kDataType_Max][4] = { constexpr VkFormat kVkDataType[eng::kDataType_Max][4] = {
{ {
VK_FORMAT_R8_UINT, VK_FORMAT_R8_UNORM,
VK_FORMAT_R8G8_UINT, VK_FORMAT_R8G8_UNORM,
VK_FORMAT_R8G8B8_UINT, VK_FORMAT_R8G8B8_UNORM,
VK_FORMAT_R8G8B8A8_UINT, VK_FORMAT_R8G8B8A8_UNORM,
}, },
{ {
VK_FORMAT_R32_SFLOAT, VK_FORMAT_R32_SFLOAT,
@ -400,7 +400,8 @@ uint64_t RendererVulkan::CreateGeometry(std::unique_ptr<Mesh> mesh) {
if (mesh->GetIndices()) { if (mesh->GetIndices()) {
geometry.num_indices = mesh->num_indices(); geometry.num_indices = mesh->num_indices();
geometry.index_type = GetIndexType(mesh->index_description()); geometry.index_type = GetIndexType(mesh->index_description());
index_data_size = mesh->GetIndexSize() * geometry.num_indices; geometry.index_type_size = mesh->GetIndexSize();
index_data_size = geometry.index_type_size * geometry.num_indices;
} }
size_t data_size = vertex_data_size + index_data_size; size_t data_size = vertex_data_size + index_data_size;
@ -414,11 +415,11 @@ uint64_t RendererVulkan::CreateGeometry(std::unique_ptr<Mesh> mesh) {
std::get<0>(geometry.buffer), 0, std::get<0>(geometry.buffer), 0,
mesh->GetVertices(), vertex_data_size)); mesh->GetVertices(), vertex_data_size));
if (geometry.num_indices > 0) { if (geometry.num_indices > 0) {
geometry.indices_offset = vertex_data_size; geometry.index_data_offset = vertex_data_size;
task_runner_.PostTask( task_runner_.PostTask(HERE, std::bind(&RendererVulkan::UpdateBuffer, this,
HERE, std::bind(&RendererVulkan::UpdateBuffer, this, std::get<0>(geometry.buffer),
std::get<0>(geometry.buffer), geometry.indices_offset, geometry.index_data_offset,
mesh->GetIndices(), index_data_size)); mesh->GetIndices(), index_data_size));
} }
task_runner_.PostTask(HERE, task_runner_.PostTask(HERE,
std::bind(&RendererVulkan::BufferMemoryBarrier, this, std::bind(&RendererVulkan::BufferMemoryBarrier, this,
@ -442,20 +443,27 @@ void RendererVulkan::DestroyGeometry(uint64_t resource_id) {
geometries_.erase(it); geometries_.erase(it);
} }
void RendererVulkan::Draw(uint64_t resource_id) { void RendererVulkan::Draw(uint64_t resource_id,
uint64_t num_indices,
uint64_t start_offset) {
auto it = geometries_.find(resource_id); auto it = geometries_.find(resource_id);
if (it == geometries_.end()) if (it == geometries_.end())
return; return;
uint64_t data_offset = start_offset * it->second.index_type_size;
if (num_indices == 0)
num_indices = it->second.num_indices;
VkDeviceSize offset = 0; VkDeviceSize offset = 0;
vkCmdBindVertexBuffers(frames_[current_frame_].draw_command_buffer, 0, 1, vkCmdBindVertexBuffers(frames_[current_frame_].draw_command_buffer, 0, 1,
&std::get<0>(it->second.buffer), &offset); &std::get<0>(it->second.buffer), &offset);
if (it->second.num_indices > 0) { if (num_indices > 0) {
vkCmdBindIndexBuffer(frames_[current_frame_].draw_command_buffer, vkCmdBindIndexBuffer(frames_[current_frame_].draw_command_buffer,
std::get<0>(it->second.buffer), std::get<0>(it->second.buffer),
it->second.indices_offset, it->second.index_type); it->second.index_data_offset + data_offset,
vkCmdDrawIndexed(frames_[current_frame_].draw_command_buffer, it->second.index_type);
it->second.num_indices, 1, 0, 0, 0); vkCmdDrawIndexed(frames_[current_frame_].draw_command_buffer, num_indices,
1, 0, 0, 0);
} else { } else {
vkCmdDraw(frames_[current_frame_].draw_command_buffer, vkCmdDraw(frames_[current_frame_].draw_command_buffer,
it->second.num_vertices, 1, 0, 0); it->second.num_vertices, 1, 0, 0);

View File

@ -35,7 +35,9 @@ class RendererVulkan final : public Renderer {
uint64_t CreateGeometry(std::unique_ptr<Mesh> mesh) final; uint64_t CreateGeometry(std::unique_ptr<Mesh> mesh) final;
void DestroyGeometry(uint64_t resource_id) final; void DestroyGeometry(uint64_t resource_id) final;
void Draw(uint64_t resource_id) final; void Draw(uint64_t resource_id,
uint64_t num_indices = 0,
uint64_t start_offset = 0) final;
uint64_t CreateTexture() final; uint64_t CreateTexture() final;
void UpdateTexture(uint64_t resource_id, std::unique_ptr<Image> image) final; void UpdateTexture(uint64_t resource_id, std::unique_ptr<Image> image) final;
@ -101,7 +103,8 @@ class RendererVulkan final : public Renderer {
Buffer<VkBuffer> buffer; Buffer<VkBuffer> buffer;
uint32_t num_vertices = 0; uint32_t num_vertices = 0;
uint32_t num_indices = 0; uint32_t num_indices = 0;
uint64_t indices_offset = 0; uint64_t index_data_offset = 0;
uint64_t index_type_size = 0;
VkIndexType index_type = VK_INDEX_TYPE_UINT16; VkIndexType index_type = VK_INDEX_TYPE_UINT16;
}; };