168 lines
3.5 KiB
C++
168 lines
3.5 KiB
C++
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
|
|
|
#include "VAOCache.h"
|
|
|
|
#if GRAPHICS_API_OPENGL
|
|
|
|
#include "TextureOGL.h"
|
|
#include "BufferOGL.h"
|
|
#include "RenderToolsOGL.h"
|
|
#include "Shaders/GPUShaderProgramOGL.h"
|
|
|
|
VAOCache::VAOCache()
|
|
: Table(2048)
|
|
{
|
|
}
|
|
|
|
VAOCache::~VAOCache()
|
|
{
|
|
Dispose();
|
|
}
|
|
|
|
GLuint VAOCache::GetVAO(GPUShaderProgramVSOGL* vs, BufferOGL* indexBuffer, uint32 streamsCount, StreamData streams[])
|
|
{
|
|
Key key(vs, indexBuffer, streamsCount, streams);
|
|
GLuint vao;
|
|
|
|
if (!Table.TryGet(key, vao))
|
|
{
|
|
// Create new VAO
|
|
glGenVertexArrays(1, &vao);
|
|
VALIDATE_OPENGL_RESULT();
|
|
|
|
// Bind VAO
|
|
glBindVertexArray(vao);
|
|
VALIDATE_OPENGL_RESULT();
|
|
|
|
// Initialize VAO
|
|
for (int32 i = 0; i < vs->Layout.Count(); i++)
|
|
{
|
|
auto& item = vs->Layout[i];
|
|
|
|
auto bufferSlot = item.BufferSlot;
|
|
if (bufferSlot >= streamsCount)
|
|
{
|
|
LOG(Error, "Incorrect input buffer slot");
|
|
continue;
|
|
}
|
|
|
|
auto& stream = streams[bufferSlot];
|
|
ASSERT(stream.Buffer != nullptr && stream.Buffer->BufferId != 0);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, stream.Buffer->BufferId);
|
|
VALIDATE_OPENGL_RESULT();
|
|
|
|
GLvoid* DataStartOffset = reinterpret_cast<GLvoid*>(static_cast<size_t>(stream.Offset + item.RelativeOffset));
|
|
if (item.IsInteger)
|
|
glVertexAttribIPointer(i, item.TypeCount, item.GlType, stream.Stride, DataStartOffset);
|
|
else
|
|
glVertexAttribPointer(i, item.TypeCount, item.GlType, item.Normalized, stream.Stride, DataStartOffset);
|
|
VALIDATE_OPENGL_RESULT();
|
|
|
|
glVertexAttribDivisor(i, item.InstanceDataStepRate);
|
|
VALIDATE_OPENGL_RESULT();
|
|
|
|
glEnableVertexAttribArray(i);
|
|
VALIDATE_OPENGL_RESULT();
|
|
}
|
|
if (indexBuffer)
|
|
{
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer->BufferId);
|
|
}
|
|
|
|
// Register in cache
|
|
Table.Add(key, vao);
|
|
}
|
|
|
|
return vao;
|
|
}
|
|
|
|
void VAOCache::OnObjectRelease(GPUShaderProgramVSOGL* obj)
|
|
{
|
|
for (auto i = Table.Begin(); i.IsNotEnd(); ++i)
|
|
{
|
|
if (i->Key.HasReference(obj))
|
|
{
|
|
GLuint fbo = i->Value;
|
|
glDeleteVertexArrays(1, &fbo);
|
|
Table.Remove(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
void VAOCache::OnObjectRelease(BufferOGL* obj)
|
|
{
|
|
for (auto i = Table.Begin(); i.IsNotEnd(); ++i)
|
|
{
|
|
if (i->Key.HasReference(obj))
|
|
{
|
|
GLuint fbo = i->Value;
|
|
glDeleteVertexArrays(1, &fbo);
|
|
Table.Remove(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
void VAOCache::Dispose()
|
|
{
|
|
for (auto i = Table.Begin(); i.IsNotEnd(); ++i)
|
|
{
|
|
GLuint fbo = i->Value;
|
|
glDeleteVertexArrays(1, &fbo);
|
|
}
|
|
Table.Clear();
|
|
}
|
|
|
|
VAOCache::Key::Key(GPUShaderProgramVSOGL* vs, BufferOGL* indexBuffer, uint32 streamsCount, StreamData streams[])
|
|
{
|
|
VS = vs;
|
|
IndexBuffer = indexBuffer;
|
|
StreamsCount = streamsCount;
|
|
|
|
Hash = streamsCount * 371;
|
|
HashCombinePointer(Hash, vs);
|
|
HashCombinePointer(Hash, indexBuffer);
|
|
|
|
for (int32 i = 0; i < streamsCount; i++)
|
|
{
|
|
Streams[i] = streams[i];
|
|
HashCombinePointer(Hash, streams[i].Buffer);
|
|
HashCombine(Hash, streams[i].Offset);
|
|
HashCombine(Hash, streams[i].Stride);
|
|
}
|
|
}
|
|
|
|
bool VAOCache::Key::HasReference(GPUShaderProgramVSOGL* obj)
|
|
{
|
|
return obj == VS;
|
|
}
|
|
|
|
bool VAOCache::Key::HasReference(BufferOGL* obj)
|
|
{
|
|
for (int32 i = 0; i < ARRAY_COUNT(Streams); i++)
|
|
{
|
|
if (Streams[i].Buffer == obj)
|
|
return true;
|
|
}
|
|
return IndexBuffer == obj;
|
|
}
|
|
|
|
bool VAOCache::Key::operator==(const Key & other) const
|
|
{
|
|
if (Hash != 0 && other.Hash != 0 && Hash != other.Hash)
|
|
return false;
|
|
|
|
if (StreamsCount != other.StreamsCount || IndexBuffer != other.IndexBuffer)
|
|
return false;
|
|
|
|
for (int32 rt = 0; rt < StreamsCount; rt++)
|
|
{
|
|
if (Streams[rt] != other.Streams[rt])
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
#endif
|