Index: binaries/data/mods/public/shaders/glsl/minimap.vs =================================================================== --- binaries/data/mods/public/shaders/glsl/minimap.vs +++ binaries/data/mods/public/shaders/glsl/minimap.vs @@ -27,23 +27,34 @@ attribute vec2 a_vertex; #endif +#if MINIMAP_POINT && USE_GPU_INSTANCING +attribute vec2 a_uv1; +attribute vec4 a_uv2; + +uniform float width; +#endif + void main() { - #if MINIMAP_BASE || MINIMAP_LOS - gl_Position = transform * vec4(a_vertex, 1.0); - v_tex = (textureTransform * vec4(a_uv0, 0.0, 1.0)).xy; - #endif +#if MINIMAP_BASE || MINIMAP_LOS + gl_Position = transform * vec4(a_vertex, 1.0); + v_tex = (textureTransform * vec4(a_uv0, 0.0, 1.0)).xy; +#endif - #if MINIMAP_MASK - v_maskUV = (maskTextureTransform * vec4(a_uv0, 0.0, 1.0)).xy; - #endif +#if MINIMAP_MASK + v_maskUV = (maskTextureTransform * vec4(a_uv0, 0.0, 1.0)).xy; +#endif - #if MINIMAP_POINT - gl_Position = transform * vec4(a_vertex, 0.0, 1.0); - color = a_color; - #endif +#if MINIMAP_POINT +#if USE_GPU_INSTANCING + gl_Position = transform * vec4(a_vertex * width + a_uv1, 0.0, 1.0); +#else + gl_Position = transform * vec4(a_vertex, 0.0, 1.0); +#endif + color = a_color; +#endif // MINIMAP_POINT - #if MINIMAP_LINE - gl_Position = transform * vec4(a_vertex, 0.0, 1.0); - #endif +#if MINIMAP_LINE + gl_Position = transform * vec4(a_vertex, 0.0, 1.0); +#endif } Index: binaries/data/mods/public/shaders/glsl/minimap.xml =================================================================== --- binaries/data/mods/public/shaders/glsl/minimap.xml +++ binaries/data/mods/public/shaders/glsl/minimap.xml @@ -4,6 +4,7 @@ + Index: source/graphics/Canvas2D.cpp =================================================================== --- source/graphics/Canvas2D.cpp +++ source/graphics/Canvas2D.cpp @@ -69,13 +69,17 @@ deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, 0); + Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::UV0, - Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, 1); + Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 1); - deviceCommandContext->SetVertexBufferData(0, vertices.data()); - deviceCommandContext->SetVertexBufferData(1, uvs.data()); + deviceCommandContext->SetVertexBufferData( + 0, vertices.data(), vertices.size() * sizeof(vertices[0])); + deviceCommandContext->SetVertexBufferData( + 1, uvs.data(), uvs.size() * sizeof(uvs[0])); deviceCommandContext->Draw(0, vertices.size() / 2); } @@ -288,15 +292,17 @@ m->DeviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, 0); + Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); m->DeviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::UV0, - Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, 1); + Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 1); - m->DeviceCommandContext->SetVertexBufferData(0, vertices.data()); - m->DeviceCommandContext->SetVertexBufferData(1, uvs.data()); + m->DeviceCommandContext->SetVertexBufferData(0, vertices.data(), vertices.size() * sizeof(vertices[0])); + m->DeviceCommandContext->SetVertexBufferData(1, uvs.data(), uvs.size() * sizeof(uvs[0])); - m->DeviceCommandContext->SetIndexBufferData(indices.data()); + m->DeviceCommandContext->SetIndexBufferData(indices.data(), indices.size() * sizeof(indices[0])); m->DeviceCommandContext->DrawIndexed(0, indices.size(), 0); } Index: source/graphics/LOSTexture.cpp =================================================================== --- source/graphics/LOSTexture.cpp +++ source/graphics/LOSTexture.cpp @@ -188,13 +188,17 @@ deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, 0); + Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::UV0, - Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, 1); + Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 1); - deviceCommandContext->SetVertexBufferData(0, quadVerts); - deviceCommandContext->SetVertexBufferData(1, quadTex); + deviceCommandContext->SetVertexBufferData( + 0, quadVerts, std::size(quadVerts) * sizeof(quadVerts[0])); + deviceCommandContext->SetVertexBufferData( + 1, quadTex, std::size(quadTex) * sizeof(quadTex[0])); deviceCommandContext->Draw(0, 6); Index: source/graphics/MiniMapTexture.h =================================================================== --- source/graphics/MiniMapTexture.h +++ source/graphics/MiniMapTexture.h @@ -104,6 +104,11 @@ VertexArray::Attribute m_AttributePos; VertexArray::Attribute m_AttributeColor; + bool m_UseInstancing = false; + // Vertex data if instancing is supported. + VertexArray m_InstanceVertexArray; + VertexArray::Attribute m_InstanceAttributePosition; + size_t m_EntitiesDrawn = 0; double m_PingDuration = 25.0; Index: source/graphics/MiniMapTexture.cpp =================================================================== --- source/graphics/MiniMapTexture.cpp +++ source/graphics/MiniMapTexture.cpp @@ -36,6 +36,7 @@ #include "ps/CStrInternStatic.h" #include "ps/Filesystem.h" #include "ps/Game.h" +#include "ps/VideoMode.h" #include "ps/World.h" #include "ps/XML/Xeromyces.h" #include "renderer/backend/IDevice.h" @@ -49,6 +50,8 @@ #include "simulation2/components/ICmpRangeManager.h" #include "simulation2/system/ParamNode.h" +#include + namespace { @@ -96,13 +99,17 @@ deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, 0); + Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::UV0, - Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, 1); + Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 1); - deviceCommandContext->SetVertexBufferData(0, quadVertices); - deviceCommandContext->SetVertexBufferData(1, quadUVs); + deviceCommandContext->SetVertexBufferData( + 0, quadVertices, std::size(quadVertices) * sizeof(quadVertices[0])); + deviceCommandContext->SetVertexBufferData( + 1, quadUVs, std::size(quadUVs) * sizeof(quadUVs[0])); deviceCommandContext->Draw(0, 6); } @@ -118,8 +125,24 @@ inline void AddEntity(const MinimapUnitVertex& v, VertexArrayIterator& attrColor, VertexArrayIterator& attrPos, - const float entityRadius) + const float entityRadius, + const bool useInstancing) { + if (useInstancing) + { + (*attrColor)[0] = v.r; + (*attrColor)[1] = v.g; + (*attrColor)[2] = v.b; + (*attrColor)[3] = v.a; + ++attrColor; + + (*attrPos)[0] = v.position.X; + (*attrPos)[1] = v.position.Y; + ++attrPos; + + return; + } + const CVector2D offsets[4] = { {-entityRadius, 0.0f}, @@ -146,7 +169,8 @@ CMiniMapTexture::CMiniMapTexture(CSimulation2& simulation) : m_Simulation(simulation), m_IndexArray(false), - m_VertexArray(Renderer::Backend::IBuffer::Type::VERTEX, true) + m_VertexArray(Renderer::Backend::IBuffer::Type::VERTEX, true), + m_InstanceVertexArray(Renderer::Backend::IBuffer::Type::VERTEX, false) { // Register Relax NG validator. CXeromyces::AddValidator(g_VFS, "pathfinder", "simulation/data/pathfinder.rng"); @@ -194,6 +218,42 @@ ++attrPos; } m_VertexArray.Upload(); + + if (g_VideoMode.GetBackendDevice()->GetCapabilities().instancing) + { + m_UseInstancing = true; + + const size_t numberOfCircleSegments = 8; + + m_InstanceAttributePosition.format = Renderer::Backend::Format::R32G32_SFLOAT; + m_InstanceVertexArray.AddAttribute(&m_InstanceAttributePosition); + + m_InstanceVertexArray.SetNumberOfVertices(numberOfCircleSegments * 3); + m_InstanceVertexArray.Layout(); + + VertexArrayIterator attributePosition = + m_InstanceAttributePosition.GetIterator(); + for (size_t segment = 0; segment < numberOfCircleSegments; ++segment) + { + const float currentAngle = static_cast(segment) / numberOfCircleSegments * 2.0f * M_PI; + const float nextAngle = static_cast(segment + 1) / numberOfCircleSegments * 2.0f * M_PI; + + (*attributePosition)[0] = 0.0f; + (*attributePosition)[1] = 0.0f; + ++attributePosition; + + (*attributePosition)[0] = std::cos(currentAngle); + (*attributePosition)[1] = std::sin(currentAngle); + ++attributePosition; + + (*attributePosition)[0] = std::cos(nextAngle); + (*attributePosition)[1] = std::sin(nextAngle); + ++attributePosition; + } + + m_InstanceVertexArray.Upload(); + m_InstanceVertexArray.FreeBackingStore(); + } } CMiniMapTexture::~CMiniMapTexture() @@ -448,25 +508,11 @@ deviceCommandContext->EndPass(); - CShaderDefines pointDefines; - pointDefines.Add(str_MINIMAP_POINT, str_1); - tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, pointDefines); - deviceCommandContext->SetGraphicsPipelineState( - tech->GetGraphicsPipelineStateDesc()); - deviceCommandContext->BeginPass(); - shader = tech->GetShader(); - deviceCommandContext->SetUniform( - shader->GetBindingSlot(str_transform), baseTransform.AsFloatArray()); - - CMatrix3D unitMatrix; - unitMatrix.SetIdentity(); - // Convert world space coordinates into [0, 2]. - const float unitScale = invTileMapSize; - unitMatrix.Scale(unitScale * 2.0f, unitScale * 2.0f, 1.0f); - // Offset the coordinates to [-1, 1]. - unitMatrix.Translate(CVector3D(-1.0f, -1.0f, 0.0f)); - deviceCommandContext->SetUniform( - shader->GetBindingSlot(str_transform), unitMatrix.AsFloatArray()); + // We might scale entities properly in the vertex shader but it requires + // additional space in the vertex buffer. So we assume that we don't need + // to change an entity size so often. + // Radius with instancing is lower because an entity has a more round shape. + const float entityRadius = static_cast(m_MapSize) / 128.0f * (m_UseInstancing ? 5.0 : 6.0f); if (doUpdate) { @@ -482,11 +528,6 @@ std::vector pingingVertices; pingingVertices.reserve(MAX_ENTITIES_DRAWN / 2); - // We might scale entities properly in the vertex shader but it requires - // additional space in the vertex buffer. So we assume that we don't need - // to change an entity size so often. - const float entityRadius = static_cast(m_MapSize) / 128.0f * 6.0f; - if (currentTime > m_NextBlinkTime) { m_BlinkState = !m_BlinkState; @@ -525,7 +566,7 @@ } else { - AddEntity(v, attrColor, attrPos, entityRadius); + AddEntity(v, attrColor, attrPos, entityRadius, m_UseInstancing); ++m_EntitiesDrawn; } @@ -554,60 +595,118 @@ // Add the pinged vertices at the end, so they are drawn on top for (const MinimapUnitVertex& vertex : pingingVertices) { - AddEntity(vertex, attrColor, attrPos, entityRadius); + AddEntity(vertex, attrColor, attrPos, entityRadius, m_UseInstancing); ++m_EntitiesDrawn; } ENSURE(m_EntitiesDrawn < MAX_ENTITIES_DRAWN); - VertexArrayIterator index = m_IndexArray.GetIterator(); - for (size_t entityIndex = 0; entityIndex < m_EntitiesDrawn; ++entityIndex) + if (!m_UseInstancing) { - index[entityIndex * 6 + 0] = static_cast(entityIndex * 4 + 0); - index[entityIndex * 6 + 1] = static_cast(entityIndex * 4 + 1); - index[entityIndex * 6 + 2] = static_cast(entityIndex * 4 + 2); - index[entityIndex * 6 + 3] = static_cast(entityIndex * 4 + 0); - index[entityIndex * 6 + 4] = static_cast(entityIndex * 4 + 2); - index[entityIndex * 6 + 5] = static_cast(entityIndex * 4 + 3); + VertexArrayIterator index = m_IndexArray.GetIterator(); + for (size_t entityIndex = 0; entityIndex < m_EntitiesDrawn; ++entityIndex) + { + index[entityIndex * 6 + 0] = static_cast(entityIndex * 4 + 0); + index[entityIndex * 6 + 1] = static_cast(entityIndex * 4 + 1); + index[entityIndex * 6 + 2] = static_cast(entityIndex * 4 + 2); + index[entityIndex * 6 + 3] = static_cast(entityIndex * 4 + 0); + index[entityIndex * 6 + 4] = static_cast(entityIndex * 4 + 2); + index[entityIndex * 6 + 5] = static_cast(entityIndex * 4 + 3); + } + + m_IndexArray.Upload(); } m_VertexArray.Upload(); - m_IndexArray.Upload(); } m_VertexArray.PrepareForRendering(); if (m_EntitiesDrawn > 0) { + CShaderDefines pointDefines; + pointDefines.Add(str_MINIMAP_POINT, str_1); + if (m_UseInstancing) + pointDefines.Add(str_USE_GPU_INSTANCING, str_1); + tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, pointDefines); + deviceCommandContext->SetGraphicsPipelineState( + tech->GetGraphicsPipelineStateDesc()); + deviceCommandContext->BeginPass(); + shader = tech->GetShader(); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_transform), baseTransform.AsFloatArray()); + + CMatrix3D unitMatrix; + unitMatrix.SetIdentity(); + // Convert world space coordinates into [0, 2]. + const float unitScale = invTileMapSize; + unitMatrix.Scale(unitScale * 2.0f, unitScale * 2.0f, 1.0f); + // Offset the coordinates to [-1, 1]. + unitMatrix.Translate(CVector3D(-1.0f, -1.0f, 0.0f)); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_transform), unitMatrix.AsFloatArray()); + Renderer::Backend::IDeviceCommandContext::Rect scissorRect; scissorRect.x = scissorRect.y = 1; scissorRect.width = scissorRect.height = FINAL_TEXTURE_SIZE - 2; deviceCommandContext->SetScissors(1, &scissorRect); m_VertexArray.UploadIfNeeded(deviceCommandContext); - m_IndexArray.UploadIfNeeded(deviceCommandContext); const uint32_t stride = m_VertexArray.GetStride(); const uint32_t firstVertexOffset = m_VertexArray.GetOffset() * stride; - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::POSITION, - m_AttributePos.format, firstVertexOffset + m_AttributePos.offset, stride, 0); - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::COLOR, - m_AttributeColor.format, firstVertexOffset + m_AttributeColor.offset, stride, 0); + if (m_UseInstancing) + { + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::POSITION, + m_AttributePos.format, + m_InstanceVertexArray.GetOffset() + m_InstanceAttributePosition.offset, + m_InstanceVertexArray.GetStride(), + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::UV1, + m_AttributePos.format, firstVertexOffset + m_AttributePos.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_INSTANCE, 1); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::COLOR, + m_AttributeColor.format, firstVertexOffset + m_AttributeColor.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_INSTANCE, 1); + + deviceCommandContext->SetVertexBuffer(0, m_InstanceVertexArray.GetBuffer()); + deviceCommandContext->SetVertexBuffer(1, m_VertexArray.GetBuffer()); - deviceCommandContext->SetVertexBuffer(0, m_VertexArray.GetBuffer()); - deviceCommandContext->SetIndexBuffer(m_IndexArray.GetBuffer()); + deviceCommandContext->SetUniform(shader->GetBindingSlot(str_width), entityRadius); + + deviceCommandContext->DrawInstanced(0, m_InstanceVertexArray.GetNumberOfVertices(), 0, m_EntitiesDrawn); + } + else + { + m_IndexArray.UploadIfNeeded(deviceCommandContext); - deviceCommandContext->DrawIndexed(m_IndexArray.GetOffset(), m_EntitiesDrawn * 6, 0); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::POSITION, + m_AttributePos.format, firstVertexOffset + m_AttributePos.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexAttributeFormat( + Renderer::Backend::VertexAttributeStream::COLOR, + m_AttributeColor.format, firstVertexOffset + m_AttributeColor.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + + deviceCommandContext->SetVertexBuffer(0, m_VertexArray.GetBuffer()); + deviceCommandContext->SetIndexBuffer(m_IndexArray.GetBuffer()); + + deviceCommandContext->DrawIndexed(m_IndexArray.GetOffset(), m_EntitiesDrawn * 6, 0); + } g_Renderer.GetStats().m_DrawCalls++; deviceCommandContext->SetScissors(0, nullptr); + + deviceCommandContext->EndPass(); } - deviceCommandContext->EndPass(); deviceCommandContext->SetFramebuffer( deviceCommandContext->GetDevice()->GetCurrentBackbuffer()); g_Renderer.SetViewport(oldViewPort); Index: source/graphics/ParticleEmitter.cpp =================================================================== --- source/graphics/ParticleEmitter.cpp +++ source/graphics/ParticleEmitter.cpp @@ -214,16 +214,20 @@ deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::POSITION, - m_AttributePos.format, firstVertexOffset + m_AttributePos.offset, stride, 0); + m_AttributePos.format, firstVertexOffset + m_AttributePos.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::COLOR, - m_AttributeColor.format, firstVertexOffset + m_AttributeColor.offset, stride, 0); + m_AttributeColor.format, firstVertexOffset + m_AttributeColor.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::UV0, - m_AttributeUV.format, firstVertexOffset + m_AttributeUV.offset, stride, 0); + m_AttributeUV.format, firstVertexOffset + m_AttributeUV.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::UV1, - m_AttributeAxis.format, firstVertexOffset + m_AttributeAxis.offset, stride, 0); + m_AttributeAxis.format, firstVertexOffset + m_AttributeAxis.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexBuffer(0, m_VertexArray.GetBuffer()); deviceCommandContext->SetIndexBuffer(m_IndexArray.GetBuffer()); Index: source/graphics/TextRenderer.cpp =================================================================== --- source/graphics/TextRenderer.cpp +++ source/graphics/TextRenderer.cpp @@ -277,13 +277,16 @@ deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R16G16_SINT, offsetof(t2f_v2i, x), stride, 0); + Renderer::Backend::Format::R16G16_SINT, offsetof(t2f_v2i, x), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::UV0, - Renderer::Backend::Format::R32G32_SFLOAT, offsetof(t2f_v2i, u), stride, 0); + Renderer::Backend::Format::R32G32_SFLOAT, offsetof(t2f_v2i, u), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - deviceCommandContext->SetVertexBufferData(0, vertexes.data()); - deviceCommandContext->SetIndexBufferData(indexes.data()); + deviceCommandContext->SetVertexBufferData( + 0, vertexes.data(), vertexes.size() * sizeof(vertexes[0])); + deviceCommandContext->SetIndexBufferData(indexes.data(), indexes.size() * sizeof(indexes[0])); deviceCommandContext->DrawIndexed(0, idx * 6, 0); idx = 0; Index: source/gui/ObjectTypes/CMiniMap.cpp =================================================================== --- source/gui/ObjectTypes/CMiniMap.cpp +++ source/gui/ObjectTypes/CMiniMap.cpp @@ -127,13 +127,17 @@ deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, 0); + Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::UV0, - Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, 1); + Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 1); - deviceCommandContext->SetVertexBufferData(0, quadVerts); - deviceCommandContext->SetVertexBufferData(1, quadTex); + deviceCommandContext->SetVertexBufferData( + 0, quadVerts, std::size(quadVerts) * sizeof(quadVerts[0])); + deviceCommandContext->SetVertexBufferData( + 1, quadTex, std::size(quadTex) * sizeof(quadTex[0])); deviceCommandContext->Draw(0, 6); } Index: source/ps/CStrInternStatic.h =================================================================== --- source/ps/CStrInternStatic.h +++ source/ps/CStrInternStatic.h @@ -68,6 +68,7 @@ X(SHADOWS_CASCADE_COUNT) X(USE_FANCY_EFFECTS) X(USE_FP_SHADOW) +X(USE_GPU_INSTANCING) X(USE_GPU_SKINNING) X(USE_INSTANCING) X(USE_NORMALS) Index: source/renderer/DebugRenderer.cpp =================================================================== --- source/renderer/DebugRenderer.cpp +++ source/renderer/DebugRenderer.cpp @@ -126,8 +126,10 @@ deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, 0); - deviceCommandContext->SetVertexBufferData(0, vertices.data()); + Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexBufferData( + 0, vertices.data(), vertices.size() * sizeof(vertices[0])); deviceCommandContext->Draw(0, vertices.size() / 3); @@ -179,8 +181,10 @@ deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, 0); - deviceCommandContext->SetVertexBufferData(0, vertices.data()); + Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexBufferData( + 0, vertices.data(), vertices.size() * sizeof(vertices[0])); deviceCommandContext->Draw(0, vertices.size() / 3); @@ -257,8 +261,10 @@ deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, 0); - deviceCommandContext->SetVertexBufferData(0, vertices.data()); + Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexBufferData( + 0, vertices.data(), vertices.size() * sizeof(vertices[0])); deviceCommandContext->Draw(0, vertices.size() / 3); @@ -278,8 +284,10 @@ deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, 0); - deviceCommandContext->SetVertexBufferData(0, vertices.data()); + Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexBufferData( + 0, vertices.data(), vertices.size() * sizeof(vertices[0])); deviceCommandContext->Draw(0, vertices.size() / 3); #undef ADD @@ -337,8 +345,10 @@ deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, 0); - deviceCommandContext->SetVertexBufferData(0, data.data()); + Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexBufferData( + 0, data.data(), data.size() * sizeof(data[0])); deviceCommandContext->Draw(0, 6 * 6); @@ -389,8 +399,10 @@ deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, 0); - deviceCommandContext->SetVertexBufferData(0, data.data()); + Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexBufferData( + 0, data.data(), data.size() * sizeof(data[0])); deviceCommandContext->Draw(0, data.size() / 5); Index: source/renderer/DecalRData.cpp =================================================================== --- source/renderer/DecalRData.cpp +++ source/renderer/DecalRData.cpp @@ -238,15 +238,18 @@ deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::POSITION, Renderer::Backend::Format::R32G32B32_SFLOAT, - offsetof(SDecalVertex, m_Position), stride, 0); + offsetof(SDecalVertex, m_Position), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::NORMAL, Renderer::Backend::Format::R32G32B32_SFLOAT, - offsetof(SDecalVertex, m_Normal), stride, 0); + offsetof(SDecalVertex, m_Normal), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::UV0, Renderer::Backend::Format::R32G32_SFLOAT, - offsetof(SDecalVertex, m_UV), stride, 0); + offsetof(SDecalVertex, m_UV), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexBuffer(0, batch.vertices->m_Owner->GetBuffer()); } Index: source/renderer/HWLightingModelRenderer.cpp =================================================================== --- source/renderer/HWLightingModelRenderer.cpp +++ source/renderer/HWLightingModelRenderer.cpp @@ -200,13 +200,15 @@ deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::UV0, m->shadermodeldef->m_UVs[0].format, - firstVertexOffset + m->shadermodeldef->m_UVs[0].offset, stride, 0); + firstVertexOffset + m->shadermodeldef->m_UVs[0].offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); if (def.GetNumUVsPerVertex() >= 2) { deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::UV1, m->shadermodeldef->m_UVs[1].format, - firstVertexOffset + m->shadermodeldef->m_UVs[1].offset, stride, 0); + firstVertexOffset + m->shadermodeldef->m_UVs[1].offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); } deviceCommandContext->SetVertexBuffer(0, m->shadermodeldef->m_Array.GetBuffer()); @@ -229,11 +231,13 @@ deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::POSITION, Renderer::Backend::Format::R32G32B32_SFLOAT, - firstVertexOffset + shadermodel->m_Position.offset, stride, 1); + firstVertexOffset + shadermodel->m_Position.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 1); deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::NORMAL, Renderer::Backend::Format::R32G32B32_SFLOAT, - firstVertexOffset + shadermodel->m_Normal.offset, stride, 1); + firstVertexOffset + shadermodel->m_Normal.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 1); deviceCommandContext->SetVertexBuffer(1, shadermodel->m_Array.GetBuffer()); deviceCommandContext->SetIndexBuffer(m->shadermodeldef->m_IndexArray.GetBuffer()); Index: source/renderer/InstancingModelRenderer.cpp =================================================================== --- source/renderer/InstancingModelRenderer.cpp +++ source/renderer/InstancingModelRenderer.cpp @@ -323,11 +323,13 @@ deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::POSITION, m->imodeldef->m_Position.format, - firstVertexOffset + m->imodeldef->m_Position.offset, stride, 0); + firstVertexOffset + m->imodeldef->m_Position.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::NORMAL, m->imodeldef->m_Normal.format, - firstVertexOffset + m->imodeldef->m_Normal.offset, stride, 0); + firstVertexOffset + m->imodeldef->m_Normal.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); constexpr size_t MAX_UV = 2; for (size_t uv = 0; uv < std::min(MAX_UV, def.GetNumUVsPerVertex()); ++uv) @@ -337,7 +339,8 @@ static_cast(Renderer::Backend::VertexAttributeStream::UV0) + uv); deviceCommandContext->SetVertexAttributeFormat( stream, m->imodeldef->m_UVs[uv].format, - firstVertexOffset + m->imodeldef->m_UVs[uv].offset, stride, 0); + firstVertexOffset + m->imodeldef->m_UVs[uv].offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); } // GPU skinning requires extra attributes to compute positions/normals. @@ -346,11 +349,13 @@ deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::UV2, m->imodeldef->m_BlendJoints.format, - firstVertexOffset + m->imodeldef->m_BlendJoints.offset, stride, 0); + firstVertexOffset + m->imodeldef->m_BlendJoints.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::UV3, m->imodeldef->m_BlendWeights.format, - firstVertexOffset + m->imodeldef->m_BlendWeights.offset, stride, 0); + firstVertexOffset + m->imodeldef->m_BlendWeights.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); } if (m->calculateTangents) @@ -358,7 +363,8 @@ deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::UV4, m->imodeldef->m_Tangent.format, - firstVertexOffset + m->imodeldef->m_Tangent.offset, stride, 0); + firstVertexOffset + m->imodeldef->m_Tangent.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); } deviceCommandContext->SetVertexBuffer(0, m->imodeldef->m_Array.GetBuffer()); Index: source/renderer/OverlayRenderer.cpp =================================================================== --- source/renderer/OverlayRenderer.cpp +++ source/renderer/OverlayRenderer.cpp @@ -565,16 +565,20 @@ // to the index offset when it's supported. deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::POSITION, - m->quadAttributePos.format, firstVertexOffset + m->quadAttributePos.offset, vertexStride, 0); + m->quadAttributePos.format, firstVertexOffset + m->quadAttributePos.offset, vertexStride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::COLOR, - m->quadAttributeColor.format, firstVertexOffset + m->quadAttributeColor.offset, vertexStride, 0); + m->quadAttributeColor.format, firstVertexOffset + m->quadAttributeColor.offset, vertexStride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::UV0, - m->quadAttributeUV.format, firstVertexOffset + m->quadAttributeUV.offset, vertexStride, 0); + m->quadAttributeUV.format, firstVertexOffset + m->quadAttributeUV.offset, vertexStride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::UV1, - m->quadAttributeUV.format, firstVertexOffset + m->quadAttributeUV.offset, vertexStride, 0); + m->quadAttributeUV.format, firstVertexOffset + m->quadAttributeUV.offset, vertexStride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexBuffer(0, m->quadVertices.GetBuffer()); deviceCommandContext->SetIndexBuffer(m->quadIndices.GetBuffer()); @@ -633,12 +637,15 @@ deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, 0); + Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::UV0, - Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, 1); + Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 1); - deviceCommandContext->SetVertexBufferData(1, &uvs[0]); + deviceCommandContext->SetVertexBufferData( + 1, &uvs[0], std::size(uvs) * sizeof(uvs[0])); const int32_t baseTexBindingSlot = shader->GetBindingSlot(str_baseTex); const int32_t colorMulBindingSlot = shader->GetBindingSlot(str_colorMul); @@ -666,7 +673,8 @@ sprite->m_Position + right*sprite->m_X0 + up*sprite->m_Y1 }; - deviceCommandContext->SetVertexBufferData(0, &position[0].X); + deviceCommandContext->SetVertexBufferData( + 0, &position[0].X, std::size(position) * sizeof(position[0])); deviceCommandContext->Draw(0, 6); @@ -774,10 +782,13 @@ deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, 0); + Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - deviceCommandContext->SetVertexBufferData(0, m->sphereVertexes.data()); - deviceCommandContext->SetIndexBufferData(m->sphereIndexes.data()); + deviceCommandContext->SetVertexBufferData( + 0, m->sphereVertexes.data(), m->sphereVertexes.size() * sizeof(m->sphereVertexes[0])); + deviceCommandContext->SetIndexBufferData( + m->sphereIndexes.data(), m->sphereIndexes.size() * sizeof(m->sphereIndexes[0])); for (size_t i = 0; i < m->spheres.size(); ++i) { Index: source/renderer/PatchRData.cpp =================================================================== --- source/renderer/PatchRData.cpp +++ source/renderer/PatchRData.cpp @@ -822,15 +822,18 @@ deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::POSITION, Renderer::Backend::Format::R32G32B32_SFLOAT, - offsetof(SBaseVertex, m_Position), stride, 0); + offsetof(SBaseVertex, m_Position), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::NORMAL, Renderer::Backend::Format::R32G32B32_SFLOAT, - offsetof(SBaseVertex, m_Normal), stride, 0); + offsetof(SBaseVertex, m_Normal), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::UV0, Renderer::Backend::Format::R32G32B32_SFLOAT, - offsetof(SBaseVertex, m_Position), stride, 0); + offsetof(SBaseVertex, m_Position), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexBuffer(0, itv->first->GetBuffer()); @@ -1071,19 +1074,23 @@ deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::POSITION, Renderer::Backend::Format::R32G32B32_SFLOAT, - offsetof(SBlendVertex, m_Position), stride, 0); + offsetof(SBlendVertex, m_Position), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::NORMAL, Renderer::Backend::Format::R32G32B32_SFLOAT, - offsetof(SBlendVertex, m_Normal), stride, 0); + offsetof(SBlendVertex, m_Normal), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::UV0, Renderer::Backend::Format::R32G32B32_SFLOAT, - offsetof(SBlendVertex, m_Position), stride, 0); + offsetof(SBlendVertex, m_Position), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::UV1, Renderer::Backend::Format::R32G32_SFLOAT, - offsetof(SBlendVertex, m_AlphaUVs), stride, 0); + offsetof(SBlendVertex, m_AlphaUVs), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexBuffer(0, itv->first->GetBuffer()); } @@ -1145,13 +1152,15 @@ deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::POSITION, Renderer::Backend::Format::R32G32B32_SFLOAT, - offsetof(SBaseVertex, m_Position), stride, 0); + offsetof(SBaseVertex, m_Position), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); if (bindPositionAsTexCoord) { deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::UV0, Renderer::Backend::Format::R32G32B32_SFLOAT, - offsetof(SBaseVertex, m_Position), stride, 0); + offsetof(SBaseVertex, m_Position), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); } // Render each batch @@ -1223,7 +1232,8 @@ deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::POSITION, Renderer::Backend::Format::R32G32B32_SFLOAT, - offsetof(SSideVertex, m_Position), stride, 0); + offsetof(SSideVertex, m_Position), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); CVertexBuffer* lastVB = nullptr; for (CPatchRData* patch : patches) @@ -1492,13 +1502,15 @@ deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::POSITION, Renderer::Backend::Format::R32G32B32_SFLOAT, - firstVertexOffset + offsetof(SWaterVertex, m_Position), stride, 0); + firstVertexOffset + offsetof(SWaterVertex, m_Position), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); if (bindWaterData) { deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::UV1, Renderer::Backend::Format::R32G32_SFLOAT, - firstVertexOffset + offsetof(SWaterVertex, m_WaterData), stride, 0); + firstVertexOffset + offsetof(SWaterVertex, m_WaterData), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); } deviceCommandContext->SetVertexBuffer(0, m_VBWater->m_Owner->GetBuffer()); @@ -1527,11 +1539,13 @@ deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::POSITION, Renderer::Backend::Format::R32G32B32_SFLOAT, - firstVertexOffset + offsetof(SWaterVertex, m_Position), stride, 0); + firstVertexOffset + offsetof(SWaterVertex, m_Position), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::UV1, Renderer::Backend::Format::R32G32_SFLOAT, - firstVertexOffset + offsetof(SWaterVertex, m_WaterData), stride, 0); + firstVertexOffset + offsetof(SWaterVertex, m_WaterData), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexBuffer(0, m_VBWaterShore->m_Owner->GetBuffer()); deviceCommandContext->SetIndexBuffer(m_VBWaterIndicesShore->m_Owner->GetBuffer()); Index: source/renderer/PostprocManager.cpp =================================================================== --- source/renderer/PostprocManager.cpp +++ source/renderer/PostprocManager.cpp @@ -233,13 +233,17 @@ deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, 0); + Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::UV0, - Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, 1); + Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 1); - deviceCommandContext->SetVertexBufferData(0, quadVerts); - deviceCommandContext->SetVertexBufferData(1, quadTex); + deviceCommandContext->SetVertexBufferData( + 0, quadVerts, std::size(quadVerts) * sizeof(quadVerts[0])); + deviceCommandContext->SetVertexBufferData( + 1, quadTex, std::size(quadTex) * sizeof(quadTex[0])); deviceCommandContext->Draw(0, 6); @@ -299,13 +303,17 @@ deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, 0); + Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::UV0, - Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, 1); + Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 1); - deviceCommandContext->SetVertexBufferData(0, quadVerts); - deviceCommandContext->SetVertexBufferData(1, quadTex); + deviceCommandContext->SetVertexBufferData( + 0, quadVerts, std::size(quadVerts) * sizeof(quadVerts[0])); + deviceCommandContext->SetVertexBufferData( + 1, quadTex, std::size(quadTex) * sizeof(quadTex[0])); deviceCommandContext->Draw(0, 6); @@ -335,13 +343,17 @@ deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, 0); + Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::UV0, - Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, 1); + Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 1); - deviceCommandContext->SetVertexBufferData(0, quadVerts); - deviceCommandContext->SetVertexBufferData(1, quadTex); + deviceCommandContext->SetVertexBufferData( + 0, quadVerts, std::size(quadVerts) * sizeof(quadVerts[0])); + deviceCommandContext->SetVertexBufferData( + 1, quadTex, std::size(quadTex) * sizeof(quadTex[0])); deviceCommandContext->Draw(0, 6); @@ -465,13 +477,17 @@ deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, 0); + Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::UV0, - Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, 1); + Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 1); - deviceCommandContext->SetVertexBufferData(0, quadVerts); - deviceCommandContext->SetVertexBufferData(1, quadTex); + deviceCommandContext->SetVertexBufferData( + 0, quadVerts, std::size(quadVerts) * sizeof(quadVerts[0])); + deviceCommandContext->SetVertexBufferData( + 1, quadTex, std::size(quadTex) * sizeof(quadTex[0])); deviceCommandContext->Draw(0, 6); Index: source/renderer/SilhouetteRenderer.cpp =================================================================== --- source/renderer/SilhouetteRenderer.cpp +++ source/renderer/SilhouetteRenderer.cpp @@ -498,9 +498,11 @@ deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R16G16_SINT, 0, 0, 0); + Renderer::Backend::Format::R16G16_SINT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - deviceCommandContext->SetVertexBufferData(0, verts); + deviceCommandContext->SetVertexBufferData( + 0, verts, std::size(verts) * sizeof(verts[0])); deviceCommandContext->Draw(0, 6); } Index: source/renderer/SkyManager.cpp =================================================================== --- source/renderer/SkyManager.cpp +++ source/renderer/SkyManager.cpp @@ -254,10 +254,12 @@ deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::POSITION, m_AttributePosition.format, - firstVertexOffset + m_AttributePosition.offset, stride, 0); + firstVertexOffset + m_AttributePosition.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::UV0, m_AttributeUV.format, - firstVertexOffset + m_AttributeUV.offset, stride, 0); + firstVertexOffset + m_AttributeUV.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexBuffer(0, m_VertexArray.GetBuffer()); Index: source/renderer/TerrainOverlay.cpp =================================================================== --- source/renderer/TerrainOverlay.cpp +++ source/renderer/TerrainOverlay.cpp @@ -221,9 +221,11 @@ deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, 0); + Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - deviceCommandContext->SetVertexBufferData(0, vertices.data()); + deviceCommandContext->SetVertexBufferData( + 0, vertices.data(), vertices.size() * sizeof(vertices[0])); deviceCommandContext->Draw(0, vertices.size() / 3); @@ -286,9 +288,11 @@ deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, 0); + Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - deviceCommandContext->SetVertexBufferData(0, vertices.data()); + deviceCommandContext->SetVertexBufferData( + 0, vertices.data(), vertices.size() * sizeof(vertices[0])); deviceCommandContext->Draw(0, vertices.size() / 3); Index: source/renderer/TerrainRenderer.cpp =================================================================== --- source/renderer/TerrainRenderer.cpp +++ source/renderer/TerrainRenderer.cpp @@ -207,12 +207,15 @@ deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, 0); + Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::UV0, - Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, 0); + Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - deviceCommandContext->SetVertexBufferData(0, waterPos); + deviceCommandContext->SetVertexBufferData( + 0, waterPos, std::size(waterPos) * sizeof(waterPos[0])); deviceCommandContext->Draw(0, 6); } Index: source/renderer/TexturedLineRData.cpp =================================================================== --- source/renderer/TexturedLineRData.cpp +++ source/renderer/TexturedLineRData.cpp @@ -62,15 +62,18 @@ deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::POSITION, Renderer::Backend::Format::R32G32B32_SFLOAT, - offsetof(CTexturedLineRData::SVertex, m_Position), stride, 0); + offsetof(CTexturedLineRData::SVertex, m_Position), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::UV0, Renderer::Backend::Format::R32G32_SFLOAT, - offsetof(CTexturedLineRData::SVertex, m_UVs), stride, 0); + offsetof(CTexturedLineRData::SVertex, m_UVs), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::UV1, Renderer::Backend::Format::R32G32_SFLOAT, - offsetof(CTexturedLineRData::SVertex, m_UVs), stride, 0); + offsetof(CTexturedLineRData::SVertex, m_UVs), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexBuffer(0, m_VB->m_Owner->GetBuffer()); Index: source/renderer/WaterManager.cpp =================================================================== --- source/renderer/WaterManager.cpp +++ source/renderer/WaterManager.cpp @@ -833,28 +833,34 @@ deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::POSITION, Renderer::Backend::Format::R32G32B32_SFLOAT, - firstVertexOffset + offsetof(SWavesVertex, m_BasePosition), stride, 0); + firstVertexOffset + offsetof(SWavesVertex, m_BasePosition), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::NORMAL, Renderer::Backend::Format::R32G32_SFLOAT, - firstVertexOffset + offsetof(SWavesVertex, m_PerpVect), stride, 0); + firstVertexOffset + offsetof(SWavesVertex, m_PerpVect), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::UV0, Renderer::Backend::Format::R8G8_UINT, - firstVertexOffset + offsetof(SWavesVertex, m_UV), stride, 0); + firstVertexOffset + offsetof(SWavesVertex, m_UV), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::UV1, Renderer::Backend::Format::R32G32B32_SFLOAT, - firstVertexOffset + offsetof(SWavesVertex, m_ApexPosition), stride, 0); + firstVertexOffset + offsetof(SWavesVertex, m_ApexPosition), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::UV2, Renderer::Backend::Format::R32G32B32_SFLOAT, - firstVertexOffset + offsetof(SWavesVertex, m_SplashPosition), stride, 0); + firstVertexOffset + offsetof(SWavesVertex, m_SplashPosition), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::UV3, Renderer::Backend::Format::R32G32B32_SFLOAT, - firstVertexOffset + offsetof(SWavesVertex, m_RetreatPosition), stride, 0); + firstVertexOffset + offsetof(SWavesVertex, m_RetreatPosition), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetUniform( shader->GetBindingSlot(str_translation), m_ShoreWaves[a]->m_TimeDiff); Index: source/renderer/backend/IDevice.h =================================================================== --- source/renderer/backend/IDevice.h +++ source/renderer/backend/IDevice.h @@ -57,6 +57,7 @@ uint32_t maxSampleCount; float maxAnisotropy; uint32_t maxTextureSize; + bool instancing; }; virtual ~IDevice() {} Index: source/renderer/backend/IDeviceCommandContext.h =================================================================== --- source/renderer/backend/IDeviceCommandContext.h +++ source/renderer/backend/IDeviceCommandContext.h @@ -84,12 +84,14 @@ const Format format, const uint32_t offset, const uint32_t stride, + const VertexAttributeRate rate, const uint32_t bindingSlot) = 0; virtual void SetVertexBuffer(const uint32_t bindingSlot, IBuffer* buffer) = 0; - virtual void SetVertexBufferData(const uint32_t bindingSlot, const void* data) = 0; + virtual void SetVertexBufferData( + const uint32_t bindingSlot, const void* data, const uint32_t dataSize) = 0; virtual void SetIndexBuffer(IBuffer* buffer) = 0; - virtual void SetIndexBufferData(const void* data) = 0; + virtual void SetIndexBufferData(const void* data, const uint32_t dataSize) = 0; virtual void BeginPass() = 0; virtual void EndPass() = 0; @@ -97,6 +99,13 @@ virtual void Draw(const uint32_t firstVertex, const uint32_t vertexCount) = 0; virtual void DrawIndexed( const uint32_t firstIndex, const uint32_t indexCount, const int32_t vertexOffset) = 0; + virtual void DrawInstanced( + const uint32_t firstVertex, const uint32_t vertexCount, + const uint32_t firstInstance, const uint32_t instanceCount) = 0; + virtual void DrawIndexedInstanced( + const uint32_t firstIndex, const uint32_t indexCount, + const uint32_t firstInstance, const uint32_t instanceCount, + const int32_t vertexOffset) = 0; // TODO: should be removed when performance impact is minimal on slow hardware. virtual void DrawIndexedInRange( const uint32_t firstIndex, const uint32_t indexCount, Index: source/renderer/backend/IShaderProgram.h =================================================================== --- source/renderer/backend/IShaderProgram.h +++ source/renderer/backend/IShaderProgram.h @@ -43,6 +43,12 @@ UV7, }; +enum class VertexAttributeRate : uint32_t +{ + PER_VERTEX, + PER_INSTANCE +}; + /** * IShaderProgram is a container for multiple shaders of different types. */ Index: source/renderer/backend/dummy/Device.h =================================================================== --- source/renderer/backend/dummy/Device.h +++ source/renderer/backend/dummy/Device.h @@ -78,7 +78,7 @@ const Capabilities& GetCapabilities() const override { return m_Capabilities; } -private: +protected: std::string m_Name; std::string m_Version; Index: source/renderer/backend/dummy/Device.cpp =================================================================== --- source/renderer/backend/dummy/Device.cpp +++ source/renderer/backend/dummy/Device.cpp @@ -58,6 +58,7 @@ m_Capabilities.maxSampleCount = 4u; m_Capabilities.maxAnisotropy = 16.0f; m_Capabilities.maxTextureSize = 8192u; + m_Capabilities.instancing = true; } CDevice::~CDevice() = default; Index: source/renderer/backend/dummy/DeviceCommandContext.h =================================================================== --- source/renderer/backend/dummy/DeviceCommandContext.h +++ source/renderer/backend/dummy/DeviceCommandContext.h @@ -83,12 +83,14 @@ const Format format, const uint32_t offset, const uint32_t stride, + const VertexAttributeRate rate, const uint32_t bindingSlot) override; void SetVertexBuffer(const uint32_t bindingSlot, IBuffer* buffer) override; - void SetVertexBufferData(const uint32_t bindingSlot, const void* data) override; + void SetVertexBufferData( + const uint32_t bindingSlot, const void* data, const uint32_t dataSize) override; void SetIndexBuffer(IBuffer* buffer) override; - void SetIndexBufferData(const void* data) override; + void SetIndexBufferData(const void* data, const uint32_t dataSize) override; void BeginPass() override; void EndPass() override; @@ -96,6 +98,13 @@ void Draw(const uint32_t firstVertex, const uint32_t vertexCount) override; void DrawIndexed( const uint32_t firstIndex, const uint32_t indexCount, const int32_t vertexOffset) override; + void DrawInstanced( + const uint32_t firstVertex, const uint32_t vertexCount, + const uint32_t firstInstance, const uint32_t instanceCount) override; + void DrawIndexedInstanced( + const uint32_t firstIndex, const uint32_t indexCount, + const uint32_t firstInstance, const uint32_t instanceCount, + const int32_t vertexOffset) override; void DrawIndexedInRange( const uint32_t firstIndex, const uint32_t indexCount, const uint32_t start, const uint32_t end) override; Index: source/renderer/backend/dummy/DeviceCommandContext.cpp =================================================================== --- source/renderer/backend/dummy/DeviceCommandContext.cpp +++ source/renderer/backend/dummy/DeviceCommandContext.cpp @@ -130,7 +130,7 @@ void CDeviceCommandContext::SetVertexAttributeFormat( const VertexAttributeStream, const Format, - const uint32_t, const uint32_t, const uint32_t) + const uint32_t, const uint32_t, const VertexAttributeRate, const uint32_t) { } @@ -138,7 +138,8 @@ { } -void CDeviceCommandContext::SetVertexBufferData(const uint32_t, const void*) +void CDeviceCommandContext::SetVertexBufferData( + const uint32_t, const void*, const uint32_t) { } @@ -146,7 +147,7 @@ { } -void CDeviceCommandContext::SetIndexBufferData(const void*) +void CDeviceCommandContext::SetIndexBufferData(const void*, const uint32_t) { } @@ -163,6 +164,16 @@ } void CDeviceCommandContext::DrawIndexed(const uint32_t, const uint32_t, const int32_t) +{ +} + +void CDeviceCommandContext::DrawInstanced( + const uint32_t, const uint32_t, const uint32_t, const uint32_t) +{ +} + +void CDeviceCommandContext::DrawIndexedInstanced( + const uint32_t, const uint32_t, const uint32_t, const uint32_t, const int32_t) { } Index: source/renderer/backend/gl/Device.cpp =================================================================== --- source/renderer/backend/gl/Device.cpp +++ source/renderer/backend/gl/Device.cpp @@ -382,6 +382,16 @@ } } +#if CONFIG2_GLES + capabilities.instancing = false; +#else + capabilities.instancing = + !device->m_ARB && + (ogl_HaveVersion(3, 3) || + (ogl_HaveExtension("GL_ARB_draw_instanced") && + ogl_HaveExtension("GL_ARB_instanced_arrays"))); +#endif + return device; } Index: source/renderer/backend/gl/DeviceCommandContext.h =================================================================== --- source/renderer/backend/gl/DeviceCommandContext.h +++ source/renderer/backend/gl/DeviceCommandContext.h @@ -90,12 +90,14 @@ const Format format, const uint32_t offset, const uint32_t stride, + const VertexAttributeRate rate, const uint32_t bindingSlot) override; void SetVertexBuffer(const uint32_t bindingSlot, IBuffer* buffer) override; - void SetVertexBufferData(const uint32_t bindingSlot, const void* data) override; + void SetVertexBufferData( + const uint32_t bindingSlot, const void* data, const uint32_t dataSize) override; void SetIndexBuffer(IBuffer* buffer) override; - void SetIndexBufferData(const void* data) override; + void SetIndexBufferData(const void* data, const uint32_t dataSize) override; void BeginPass() override; void EndPass() override; @@ -103,6 +105,13 @@ void Draw(const uint32_t firstVertex, const uint32_t vertexCount) override; void DrawIndexed( const uint32_t firstIndex, const uint32_t indexCount, const int32_t vertexOffset) override; + void DrawInstanced( + const uint32_t firstVertex, const uint32_t vertexCount, + const uint32_t firstInstance, const uint32_t instanceCount) override; + void DrawIndexedInstanced( + const uint32_t firstIndex, const uint32_t indexCount, + const uint32_t firstInstance, const uint32_t instanceCount, + const int32_t vertexOffset) override; void DrawIndexedInRange( const uint32_t firstIndex, const uint32_t indexCount, const uint32_t start, const uint32_t end) override; @@ -206,6 +215,7 @@ Format format; uint32_t offset; uint32_t stride; + VertexAttributeRate rate; uint32_t bindingSlot; bool active; Index: source/renderer/backend/gl/DeviceCommandContext.cpp =================================================================== --- source/renderer/backend/gl/DeviceCommandContext.cpp +++ source/renderer/backend/gl/DeviceCommandContext.cpp @@ -834,11 +834,12 @@ } void CDeviceCommandContext::SetVertexAttributeFormat( - const VertexAttributeStream stream, - const Format format, - const uint32_t offset, - const uint32_t stride, - const uint32_t bindingSlot) + const VertexAttributeStream stream, + const Format format, + const uint32_t offset, + const uint32_t stride, + const VertexAttributeRate rate, + const uint32_t bindingSlot) { const uint32_t index = static_cast(stream); ENSURE(index < m_VertexAttributeFormat.size()); @@ -848,6 +849,7 @@ m_VertexAttributeFormat[index].format = format; m_VertexAttributeFormat[index].offset = offset; m_VertexAttributeFormat[index].stride = stride; + m_VertexAttributeFormat[index].rate = rate; m_VertexAttributeFormat[index].bindingSlot = bindingSlot; m_VertexAttributeFormat[index].initialized = true; @@ -870,15 +872,17 @@ m_VertexAttributeFormat[index].format, m_VertexAttributeFormat[index].offset, m_VertexAttributeFormat[index].stride, + m_VertexAttributeFormat[index].rate, nullptr); } } void CDeviceCommandContext::SetVertexBufferData( - const uint32_t bindingSlot, const void* data) + const uint32_t bindingSlot, const void* data, const uint32_t dataSize) { ENSURE(data); ENSURE(m_ShaderProgram); + ENSURE(dataSize > 0); BindBuffer(CBuffer::Type::VERTEX, nullptr); for (size_t index = 0; index < m_VertexAttributeFormat.size(); ++index) { @@ -886,10 +890,14 @@ continue; ENSURE(m_VertexAttributeFormat[index].initialized); const VertexAttributeStream stream = static_cast(index); + // We don't know how many vertices will be used in a draw command, so we + // assume at least one vertex. + ENSURE(dataSize >= m_VertexAttributeFormat[index].offset + m_VertexAttributeFormat[index].stride); m_ShaderProgram->VertexAttribPointer(stream, m_VertexAttributeFormat[index].format, m_VertexAttributeFormat[index].offset, m_VertexAttributeFormat[index].stride, + m_VertexAttributeFormat[index].rate, data); } } @@ -902,8 +910,9 @@ BindBuffer(CBuffer::Type::INDEX, m_IndexBuffer); } -void CDeviceCommandContext::SetIndexBufferData(const void* data) +void CDeviceCommandContext::SetIndexBufferData(const void* data, const uint32_t dataSize) { + ENSURE(dataSize > 0); if (m_IndexBuffer) { BindBuffer(CBuffer::Type::INDEX, nullptr); @@ -957,6 +966,47 @@ // in Mesa 7.10 swrast with index VBOs). glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_SHORT, static_cast((static_cast(m_IndexBufferData) + sizeof(uint16_t) * firstIndex))); + ogl_WarnIfError(); +} + +void CDeviceCommandContext::DrawInstanced( + const uint32_t firstVertex, const uint32_t vertexCount, + const uint32_t firstInstance, const uint32_t instanceCount) +{ + ENSURE(m_Device->GetCapabilities().instancing); + ENSURE(m_ShaderProgram); + ENSURE(m_InsidePass); + if (vertexCount == 0 || instanceCount == 0) + return; + ENSURE(firstInstance == 0); + m_ShaderProgram->AssertPointersBound(); + glDrawArraysInstancedARB(GL_TRIANGLES, firstVertex, vertexCount, instanceCount); + ogl_WarnIfError(); +} + +void CDeviceCommandContext::DrawIndexedInstanced( + const uint32_t firstIndex, const uint32_t indexCount, + const uint32_t firstInstance, const uint32_t instanceCount, + const int32_t vertexOffset) +{ + ENSURE(m_Device->GetCapabilities().instancing); + ENSURE(m_ShaderProgram); + ENSURE(m_InsidePass); + ENSURE(m_IndexBuffer || m_IndexBufferData); + if (indexCount == 0) + return; + ENSURE(firstInstance == 0 && vertexOffset == 0); + if (m_IndexBuffer) + { + ENSURE(sizeof(uint16_t) * (firstIndex + indexCount) <= m_IndexBuffer->GetSize()); + } + m_ShaderProgram->AssertPointersBound(); + // Don't use glMultiDrawElements here since it doesn't have a significant + // performance impact and it suffers from various driver bugs (e.g. it breaks + // in Mesa 7.10 swrast with index VBOs). + glDrawElementsInstancedARB(GL_TRIANGLES, indexCount, GL_UNSIGNED_SHORT, + static_cast((static_cast(m_IndexBufferData) + sizeof(uint16_t) * firstIndex)), + instanceCount); ogl_WarnIfError(); } Index: source/renderer/backend/gl/ShaderProgram.h =================================================================== --- source/renderer/backend/gl/ShaderProgram.h +++ source/renderer/backend/gl/ShaderProgram.h @@ -110,7 +110,8 @@ // Vertex attribute pointers (equivalent to glVertexPointer etc). virtual void VertexAttribPointer( const VertexAttributeStream stream, const Format format, - const uint32_t offset, const uint32_t stride, const void* data); + const uint32_t offset, const uint32_t stride, + const VertexAttributeRate rate, const void* data); bool IsStreamActive(const VertexAttributeStream stream) const; @@ -127,7 +128,6 @@ void NormalPointer(const Renderer::Backend::Format format, GLsizei stride, const void* pointer); void ColorPointer(const Renderer::Backend::Format format, GLsizei stride, const void* pointer); void TexCoordPointer(GLenum texture, const Renderer::Backend::Format format, GLsizei stride, const void* pointer); - void VertexAttribPointer(attrib_id_t id, const Renderer::Backend::Format format, GLboolean normalized, GLsizei stride, const void* pointer); int m_StreamFlags; Index: source/renderer/backend/gl/ShaderProgram.cpp =================================================================== --- source/renderer/backend/gl/ShaderProgram.cpp +++ source/renderer/backend/gl/ShaderProgram.cpp @@ -1088,7 +1088,8 @@ void VertexAttribPointer( const VertexAttributeStream stream, const Format format, - const uint32_t offset, const uint32_t stride, const void* data) override + const uint32_t offset, const uint32_t stride, + const VertexAttributeRate rate, const void* data) override { const int attributeLocation = GetAttributeLocationFromStream(m_Device, stream); std::vector::const_iterator it = @@ -1100,6 +1101,11 @@ const GLboolean normalized = NormalizedFromFormat(format); glVertexAttribPointer( attributeLocation, size, type, normalized, stride, static_cast(data) + offset); + if (rate == VertexAttributeRate::PER_INSTANCE) + { + ENSURE(m_Device->GetCapabilities().instancing); + glVertexAttribDivisorARB(attributeLocation, 1); + } m_ValidStreams |= GetStreamMask(stream); } @@ -1310,12 +1316,6 @@ // These should all be overridden by CShaderProgramGLSL, and not used // if a non-GLSL shader was loaded instead: -void CShaderProgram::VertexAttribPointer(attrib_id_t UNUSED(id), const Renderer::Backend::Format UNUSED(format), - GLboolean UNUSED(normalized), GLsizei UNUSED(stride), const void* UNUSED(pointer)) -{ - debug_warn("Shader type doesn't support VertexAttribPointer"); -} - #if CONFIG2_GLES // These should all be overridden by CShaderProgramGLSL @@ -1449,8 +1449,10 @@ void CShaderProgram::VertexAttribPointer( const VertexAttributeStream stream, const Format format, - const uint32_t offset, const uint32_t stride, const void* data) + const uint32_t offset, const uint32_t stride, + const VertexAttributeRate rate, const void* data) { + ENSURE(rate == VertexAttributeRate::PER_VERTEX); switch (stream) { case VertexAttributeStream::POSITION: