1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2025-12-10 09:32:29 +01:00

Implement sprite batch drawing using instancing

This commit is contained in:
Alexander Overvoorde
2016-07-23 00:56:41 +02:00
parent 84f2a8c17c
commit fbb7029de4
8 changed files with 111 additions and 85 deletions

View File

@@ -1,12 +1,13 @@
#version 150
uniform ivec4 uClip;
uniform int uFlags;
uniform vec4 uColour;
uniform usampler2DArray uTexture;
uniform vec4 uPalette[256];
uniform vec2 uTexCoordScale;
uniform int uTexSlot;
uniform usampler2DArray uTexture;
flat in ivec4 fClip;
flat in int fFlags;
in vec4 fColour;
in vec2 fTexCoordScale;
flat in int fTexSlot;
in vec2 fPosition;
in vec2 fTextureCoordinate;
@@ -15,16 +16,16 @@ out vec4 oColour;
void main()
{
if (fPosition.x < uClip.x || fPosition.x > uClip.z ||
fPosition.y < uClip.y || fPosition.y > uClip.w)
if (fPosition.x < fClip.x || fPosition.x > fClip.z ||
fPosition.y < fClip.y || fPosition.y > fClip.w)
{
discard;
}
vec4 texel = uPalette[texture(uTexture, vec3(fTextureCoordinate * uTexCoordScale, float(uTexSlot))).r];
if ((uFlags & 1) != 0)
vec4 texel = uPalette[texture(uTexture, vec3(fTextureCoordinate * fTexCoordScale, float(fTexSlot))).r];
if ((fFlags & 1) != 0)
{
oColour = vec4(uColour.rgb, uColour.a * texel.a);
oColour = vec4(fColour.rgb, fColour.a * texel.a);
}
else
{

View File

@@ -1,32 +1,43 @@
#version 150
uniform ivec2 uScreenSize;
uniform ivec4 uBounds;
uniform ivec4 uTextureCoordinates;
in ivec4 ivClip;
in vec2 ivTexCoordScale;
in int ivTexSlot;
in int ivFlags;
in vec4 ivColour;
in ivec4 ivBounds;
in uint vIndex;
out vec2 fPosition;
out vec2 fTextureCoordinate;
out vec2 fTextureCoordinate;
out vec2 fPosition;
flat out ivec4 fClip;
flat out int fFlags;
out vec4 fColour;
out vec2 fTexCoordScale;
flat out int fTexSlot;
void main()
{
vec2 pos;
switch (vIndex) {
case 0u:
pos = uBounds.xy;
pos = ivBounds.xy;
fTextureCoordinate = uTextureCoordinates.xy;
break;
case 1u:
pos = uBounds.zy;
pos = ivBounds.zy;
fTextureCoordinate = uTextureCoordinates.zy;
break;
case 2u:
pos = uBounds.xw;
pos = ivBounds.xw;
fTextureCoordinate = uTextureCoordinates.xw;
break;
case 3u:
pos = uBounds.zw;
pos = ivBounds.zw;
fTextureCoordinate = uTextureCoordinates.zw;
break;
}
@@ -38,5 +49,11 @@ void main()
pos.y = (pos.y * (2.0 / uScreenSize.y)) - 1.0;
pos.y *= -1;
fClip = ivClip;
fFlags = ivFlags;
fColour = ivColour;
fTexCoordScale = ivTexCoordScale;
fTexSlot = ivTexSlot;
gl_Position = vec4(pos, 0.0, 1.0);
}

View File

@@ -23,6 +23,7 @@ DrawImageShader::DrawImageShader() : OpenGLShaderProgram("drawimage")
GetLocations();
glGenBuffers(1, &_vbo);
glGenBuffers(1, &_vboInstances);
glGenVertexArrays(1, &_vao);
GLuint vertices[] = { 0, 1, 2, 2, 1, 3 };
@@ -34,7 +35,6 @@ DrawImageShader::DrawImageShader() : OpenGLShaderProgram("drawimage")
glVertexAttribIPointer(vIndex, 1, GL_INT, 0, nullptr);
Use();
SetFlags(0);
SetTextureCoordinates(0, 0, 1, 1);
glUniform1i(uTexture, 0);
}
@@ -42,6 +42,7 @@ DrawImageShader::DrawImageShader() : OpenGLShaderProgram("drawimage")
DrawImageShader::~DrawImageShader()
{
glDeleteBuffers(1, &_vbo);
glDeleteBuffers(1, &_vboInstances);
glDeleteVertexArrays(1, &_vao);
glBindVertexArray(_vao);
@@ -50,15 +51,9 @@ DrawImageShader::~DrawImageShader()
void DrawImageShader::GetLocations()
{
uScreenSize = GetUniformLocation("uScreenSize");
uClip = GetUniformLocation("uClip");
uBounds = GetUniformLocation("uBounds");
uTextureCoordinates = GetUniformLocation("uTextureCoordinates");
uTexture = GetUniformLocation("uTexture");
uColour = GetUniformLocation("uColour");
uFlags = GetUniformLocation("uFlags");
uPalette = GetUniformLocation("uPalette");
uTexCoordScale = GetUniformLocation("uTexCoordScale");
uTexSlot = GetUniformLocation("uTexSlot");
uTextureCoordinates = GetUniformLocation("uTextureCoordinates");
vIndex = GetAttributeLocation("vIndex");
}
@@ -68,14 +63,9 @@ void DrawImageShader::SetScreenSize(sint32 width, sint32 height)
glUniform2i(uScreenSize, width, height);
}
void DrawImageShader::SetClip(sint32 left, sint32 top, sint32 right, sint32 bottom)
void DrawImageShader::SetPalette(const vec4f *glPalette)
{
glUniform4i(uClip, left, top, right, bottom);
}
void DrawImageShader::SetBounds(sint32 left, sint32 top, sint32 right, sint32 bottom)
{
glUniform4i(uBounds, left, top, right, bottom);
glUniform4fv(uPalette, 256, (const GLfloat *) glPalette);
}
void DrawImageShader::SetTextureCoordinates(sint32 left, sint32 top, sint32 right, sint32 bottom)
@@ -83,36 +73,38 @@ void DrawImageShader::SetTextureCoordinates(sint32 left, sint32 top, sint32 righ
glUniform4i(uTextureCoordinates, left, top, right, bottom);
}
void DrawImageShader::SetTextureCoordScale(float width, float height) {
glUniform2f(uTexCoordScale, width, height);
}
void DrawImageShader::SetTextureSlot(GLuint slot)
void DrawImageShader::DrawInstances(const std::vector<DrawImageInstance>& instances)
{
glUniform1i(uTexSlot, slot);
}
void DrawImageShader::SetColour(vec4f colour)
{
glUniform4f(uColour, colour.r, colour.g, colour.b, colour.a);
}
void DrawImageShader::SetFlags(uint32 flags)
{
glUniform1i(uFlags, flags);
}
void DrawImageShader::SetPalette(const vec4f *glPalette)
{
glUniform4fv(uPalette, 256, (const GLfloat *) glPalette);
}
void DrawImageShader::Draw(sint32 left, sint32 top, sint32 right, sint32 bottom)
{
SetBounds(left, top, right, bottom);
// Copy instance data to vbo for single-use
glBindBuffer(GL_ARRAY_BUFFER, _vboInstances);
glBufferData(GL_ARRAY_BUFFER, sizeof(instances[0]) * instances.size(), instances.data(), GL_STREAM_DRAW);
// Bind vertex attributes
glBindVertexArray(_vao);
glDrawArrays(GL_TRIANGLES, 0, 6);
glVertexAttribIPointer(GetAttributeLocation("ivClip"), 4, GL_INT, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, clip));
glVertexAttribPointer(GetAttributeLocation("ivTexCoordScale"), 2, GL_FLOAT, GL_FALSE, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, texCoordScale));
glVertexAttribIPointer(GetAttributeLocation("ivTexSlot"), 1, GL_INT, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, texSlot));
glVertexAttribIPointer(GetAttributeLocation("ivFlags"), 1, GL_INT, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, flags));
glVertexAttribPointer(GetAttributeLocation("ivColour"), 4, GL_FLOAT, GL_FALSE, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, colour));
glVertexAttribIPointer(GetAttributeLocation("ivBounds"), 4, GL_INT, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, bounds));
glEnableVertexAttribArray(GetAttributeLocation("ivClip"));
glEnableVertexAttribArray(GetAttributeLocation("ivTexCoordScale"));
glEnableVertexAttribArray(GetAttributeLocation("ivTexSlot"));
glEnableVertexAttribArray(GetAttributeLocation("ivFlags"));
glEnableVertexAttribArray(GetAttributeLocation("ivColour"));
glEnableVertexAttribArray(GetAttributeLocation("ivBounds"));
glVertexAttribDivisor(GetAttributeLocation("ivClip"), 1);
glVertexAttribDivisor(GetAttributeLocation("ivTexCoordScale"), 1);
glVertexAttribDivisor(GetAttributeLocation("ivTexSlot"), 1);
glVertexAttribDivisor(GetAttributeLocation("ivFlags"), 1);
glVertexAttribDivisor(GetAttributeLocation("ivColour"), 1);
glVertexAttribDivisor(GetAttributeLocation("ivBounds"), 1);
// Draw instances
glDrawArraysInstanced(GL_TRIANGLES, 0, 6, instances.size());
}
#endif /* DISABLE_OPENGL */

View File

@@ -19,24 +19,30 @@
#include "GLSLTypes.h"
#include "OpenGLShaderProgram.h"
#include <SDL_pixels.h>
#include <vector>
// Per-instance data for images
struct DrawImageInstance {
vec4i clip;
vec2f texCoordScale;
int texSlot;
int flags;
vec4f colour;
vec4i bounds;
};
class DrawImageShader : public OpenGLShaderProgram
{
private:
GLuint uScreenSize;
GLuint uClip;
GLuint uBounds;
GLuint uTextureCoordinates;
GLuint uTexture;
GLuint uColour;
GLuint uFlags;
GLuint uPalette;
GLuint uTexCoordScale;
GLuint uTexSlot;
GLuint uTextureCoordinates;
GLuint vIndex;
GLuint _vbo;
GLuint _vboInstances;
GLuint _vao;
SDL_Color _palette[256];
@@ -46,15 +52,9 @@ public:
~DrawImageShader() override;
void SetScreenSize(sint32 width, sint32 height);
void SetClip(sint32 left, sint32 top, sint32 right, sint32 bottom);
void SetBounds(sint32 left, sint32 top, sint32 right, sint32 bottom);
void SetTextureCoordinates(sint32 left, sint32 top, sint32 right, sint32 bottom);
void SetTextureCoordScale(float width, float height);
void SetTextureSlot(GLuint slot);
void SetColour(vec4f colour);
void SetFlags(uint32 flags);
void SetPalette(const vec4f *glPalette);
void Draw(sint32 left, sint32 top, sint32 right, sint32 bottom);
void SetTextureCoordinates(sint32 left, sint32 top, sint32 right, sint32 bottom);
void DrawInstances(const std::vector<DrawImageInstance>& instances);
private:
void GetLocations();

View File

@@ -110,6 +110,8 @@ static const char * TryLoadAllProcAddresses()
SetupOpenGLFunction(glVertexAttribPointer);
SetupOpenGLFunction(glTexStorage3D);
SetupOpenGLFunction(glDebugMessageCallback);
SetupOpenGLFunction(glDrawArraysInstanced);
SetupOpenGLFunction(glVertexAttribDivisor);
return nullptr;
}

View File

@@ -162,6 +162,8 @@ GLAPI_DECL PFNGLVERTEXATTRIBIPOINTERPROC glVertexAttribIPointer GLAP
GLAPI_DECL PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer GLAPI_SET;
GLAPI_DECL PFNGLTEXSTORAGE3DPROC glTexStorage3D GLAPI_SET;
GLAPI_DECL PFNGLDEBUGMESSAGECALLBACKPROC glDebugMessageCallback GLAPI_SET;
GLAPI_DECL PFNGLDRAWARRAYSINSTANCEDPROC glDrawArraysInstanced GLAPI_SET;
GLAPI_DECL PFNGLVERTEXATTRIBDIVISORPROC glVertexAttribDivisor GLAPI_SET;
#endif /* OPENGL_NO_LINK */

View File

@@ -803,7 +803,8 @@ void OpenGLDrawingContext::DrawSpriteRawMasked(sint32 x, sint32 y, uint32 maskIm
_commandBuffers.maskedImages.push_back(command);
// Currently not properly ordered with regular images yet
FlushCommandBuffers();
// TODO: uncomment once masked images are mixed with normal images using depth sorting
//FlushCommandBuffers();
}
void OpenGLDrawingContext::DrawSpriteSolid(uint32 image, sint32 x, sint32 y, uint8 colour)
@@ -943,18 +944,29 @@ void OpenGLDrawingContext::FlushLines() {
}
void OpenGLDrawingContext::FlushImages() {
if (_commandBuffers.images.size() == 0) return;
OpenGLAPI::SetTexture(0, GL_TEXTURE_2D_ARRAY, _textureCache->GetArrayTexture());
std::vector<DrawImageInstance> instances;
instances.reserve(_commandBuffers.images.size());
for (const auto& command : _commandBuffers.images) {
_drawImageShader->Use();
_drawImageShader->SetClip(command.clip[0], command.clip[1], command.clip[2], command.clip[3]);
_drawImageShader->SetTextureCoordScale(command.texColour.dimensions.x, command.texColour.dimensions.y);
_drawImageShader->SetTextureSlot(command.texColour.slot);
_drawImageShader->SetFlags(command.flags);
_drawImageShader->SetColour(command.colour);
_drawImageShader->Draw(command.bounds[0], command.bounds[1], command.bounds[2], command.bounds[3]);
DrawImageInstance instance;
instance.clip = {command.clip[0], command.clip[1], command.clip[2], command.clip[3]};
instance.texCoordScale = command.texColour.dimensions;
instance.texSlot = command.texColour.slot;
instance.flags = command.flags;
instance.colour = command.colour;
instance.bounds = {command.bounds[0], command.bounds[1], command.bounds[2], command.bounds[3]};
instances.push_back(instance);
}
_drawImageShader->Use();
_drawImageShader->DrawInstances(instances);
_commandBuffers.images.clear();
}

View File

@@ -64,7 +64,7 @@ CachedTextureInfo TextureCache::GetOrLoadImageTexture(uint32 image)
auto cacheInfo = LoadImageTexture(image);
_imageTextureMap[image & 0x7FFFF] = cacheInfo;
printf("%d slots left\n", (int) _freeSlots.size());
//printf("%d slots left\n", (int) _freeSlots.size());
return cacheInfo;
}
@@ -86,7 +86,7 @@ CachedTextureInfo TextureCache::GetOrLoadGlyphTexture(uint32 image, uint8 * pale
auto cacheInfo = LoadGlyphTexture(image, palette);
_glyphTextureMap[glyphId] = cacheInfo;
printf("%d slots left\n", (int) _freeSlots.size());
//printf("%d slots left\n", (int) _freeSlots.size());
return cacheInfo;
}