gl_engine: make GlRenderTask generic with uniform block

* Use uniform block to pack all color informations
* Move the actual gl draw call into GlRenderer::sync function, so all
  data is been uploaded into GPU
* Make GlRenderTask simple and generic for direct gl draw
This commit is contained in:
RuiwenTang 2023-09-15 19:34:11 +08:00 committed by Hermet Park
parent 9e3b74bac5
commit 453cba7ddd
16 changed files with 412 additions and 793 deletions

View file

@ -3,16 +3,13 @@ source_file = [
'tvgGlGeometry.h',
'tvgGlGpuBuffer.h',
'tvgGlProgram.h',
'tvgGlPropertyInterface.h',
'tvgGlRenderer.h',
'tvgGlRendererProperties.h',
'tvgGlRenderTask.h',
'tvgGlShader.h',
'tvgGlShaderSrc.h',
'tvgGlGeometry.cpp',
'tvgGlGpuBuffer.cpp',
'tvgGlProgram.cpp',
'tvgGlPropertyInterface.cpp',
'tvgGlRenderer.cpp',
'tvgGlRenderTask.cpp',
'tvgGlShader.cpp',

View file

@ -61,5 +61,25 @@ struct GlShape
unique_ptr<GlGeometry> geometry;
};
#define MAX_GRADIENT_STOPS 4
struct GlLinearGradientBlock
{
alignas(16) float nStops[4] = {};
alignas(16) float startPos[2] = {};
alignas(8) float stopPos[2] = {};
alignas(8) float stopPoints[MAX_GRADIENT_STOPS] = {};
alignas(16) float stopColors[4 * MAX_GRADIENT_STOPS] = {};
};
struct GlRadialGradientBlock
{
alignas(16) float nStops[4] = {};
alignas(16) float centerPos[2] = {};
alignas(8) float radius[2] = {};
alignas(8) float stopPoints[MAX_GRADIENT_STOPS] = {};
alignas(16) float stopColors[4 * MAX_GRADIENT_STOPS] = {};
};
#endif /* _TVG_GL_COMMON_H_ */

View file

@ -24,6 +24,7 @@
#include "tvgGlGpuBuffer.h"
#include "tvgGlGeometry.h"
#include "tvgGlTessellator.h"
#include "tvgGlRenderTask.h"
#define NORMALIZED_TOP_3D 1.0f
#define NORMALIZED_BOTTOM_3D -1.0f
@ -34,39 +35,22 @@ GlGeometry::~GlGeometry()
{
}
bool GlGeometry::tesselate(const RenderShape& rshape, RenderUpdateFlag flag, GlStageBuffer* gpuBuffer)
bool GlGeometry::tesselate(const RenderShape& rshape, RenderUpdateFlag flag)
{
mFillVertexOffset = 0;
mStrokeVertexOffset = 0;
mFillIndexOffset = 0;
mStrokeIndexOffset = 0;
mFillCount = 0;
mStrokeCount = 0;
if (flag & (RenderUpdateFlag::Color | RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform)) {
Array<float> vertex;
Array<uint32_t> index;
fillVertex.clear();
fillIndex.clear();
tvg::Tessellator tess{&vertex, &index};
Tessellator tess{&fillVertex, &fillIndex};
tess.tessellate(&rshape, true);
mFillCount = index.count;
mFillVertexOffset = gpuBuffer->push(vertex.data, vertex.count * sizeof(float));
mFillIndexOffset = gpuBuffer->push(index.data, index.count * sizeof(uint32_t));
}
if (flag & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) {
Array<float> vertex;
Array<uint32_t> index;
strokeVertex.clear();
strokeIndex.clear();
tvg::Stroker stroke{&vertex, &index};
Stroker stroke{&strokeVertex, &strokeIndex};
stroke.stroke(&rshape);
mStrokeCount = index.count;
mStrokeVertexOffset = gpuBuffer->push(vertex.data, vertex.count * sizeof(float));
mStrokeIndexOffset = gpuBuffer->push(index.data, index.count * sizeof(uint32_t));
}
return true;
@ -79,22 +63,34 @@ void GlGeometry::disableVertex(uint32_t location)
}
void GlGeometry::draw(const uint32_t location, RenderUpdateFlag flag)
bool GlGeometry::draw(GlRenderTask* task, GlStageBuffer* gpuBuffer, RenderUpdateFlag flag)
{
if (flag == RenderUpdateFlag::None) {
return;
return false;
}
Array<float>* vertexBuffer = nullptr;
Array<uint32_t>* indexBuffer = nullptr;
uint32_t vertexOffset = (flag == RenderUpdateFlag::Stroke) ? mStrokeVertexOffset : mFillVertexOffset;
uint32_t indexOffset = (flag == RenderUpdateFlag::Stroke) ? mStrokeIndexOffset : mFillIndexOffset;
uint32_t count = (flag == RenderUpdateFlag::Stroke) ? mStrokeCount : mFillCount;
if (flag & RenderUpdateFlag::Stroke) {
vertexBuffer = &strokeVertex;
indexBuffer = &strokeIndex;
} else {
vertexBuffer = &fillVertex;
indexBuffer = &fillIndex;
}
GL_CHECK(glVertexAttribPointer(location, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), reinterpret_cast<void*>(vertexOffset)));
GL_CHECK(glEnableVertexAttribArray(location));
if (indexBuffer->count == 0) return false;
GL_CHECK(glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, reinterpret_cast<void*>(indexOffset)));
uint32_t vertexOffset = gpuBuffer->push(vertexBuffer->data, vertexBuffer->count * sizeof(float));
uint32_t indexOffset = gpuBuffer->push(indexBuffer->data, indexBuffer->count * sizeof(uint32_t));
// vertex layout
task->addVertexLayout(GlVertexLayout{0, 3, 3 * sizeof(float), vertexOffset});
task->setDrawRange(indexOffset, indexBuffer->count);
return true;
}

View file

@ -180,26 +180,25 @@ public:
};
class GlStageBuffer;
class GlRenderTask;
class GlGeometry
{
public:
GlGeometry() = default;
~GlGeometry();
bool tesselate(const RenderShape& rshape, RenderUpdateFlag flag, GlStageBuffer* gpuBuffer);
bool tesselate(const RenderShape& rshape, RenderUpdateFlag flag);
void disableVertex(uint32_t location);
void draw(const uint32_t location, RenderUpdateFlag flag);
bool draw(GlRenderTask* task, GlStageBuffer* gpuBuffer, RenderUpdateFlag flag);
void updateTransform(const RenderTransform* transform, float w, float h);
float* getTransforMatrix();
private:
uint32_t mFillVertexOffset;
uint32_t mFillIndexOffset;
uint32_t mFillCount;
uint32_t mStrokeVertexOffset;
uint32_t mStrokeIndexOffset;
uint32_t mStrokeCount;
Array<float> fillVertex = {};
Array<float> strokeVertex = {};
Array<uint32_t> fillIndex = {};
Array<uint32_t> strokeIndex = {};
float mTransform[16];
};

View file

@ -29,6 +29,18 @@
/* Internal Class Implementation */
/************************************************************************/
static GLint _getGpuBufferAlign()
{
static GLint offset = 0;
if (!offset)
{
GL_CHECK(glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &offset));
}
return offset;
}
GlGpuBuffer::GlGpuBuffer()
{
GL_CHECK(glGenBuffers(1, &mGlBufferId));
@ -60,6 +72,11 @@ void GlGpuBuffer::unbind(Target target)
GL_CHECK(glBindBuffer(static_cast<uint32_t>(target), 0));
}
GlStageBuffer::GlStageBuffer() : mVao(0), mGpuBuffer(new GlGpuBuffer)
{
GL_CHECK(glGenVertexArrays(1, &mVao));
}
GlStageBuffer::~GlStageBuffer()
{
if (mVao) {
@ -68,8 +85,10 @@ GlStageBuffer::~GlStageBuffer()
}
}
uint32_t GlStageBuffer::push(void *data, uint32_t size)
uint32_t GlStageBuffer::push(void *data, uint32_t size, bool alignGpuOffset)
{
if (alignGpuOffset) alignOffset();
uint32_t offset = mStageBuffer.count;
if (this->mStageBuffer.reserved - this->mStageBuffer.count < size) {
@ -87,14 +106,12 @@ void GlStageBuffer::flushToGPU()
{
if (mStageBuffer.empty()) return;
if (!mGpuBuffer) {
mGpuBuffer.reset(new GlGpuBuffer);
GL_CHECK(glGenVertexArrays(1, &mVao));
}
mGpuBuffer->bind(GlGpuBuffer::Target::ARRAY_BUFFER);
mGpuBuffer->updateBufferData(GlGpuBuffer::Target::ARRAY_BUFFER, mStageBuffer.count, mStageBuffer.data);
mGpuBuffer->unbind(GlGpuBuffer::Target::ARRAY_BUFFER);
mStageBuffer.clear();
}
void GlStageBuffer::bind()
@ -102,6 +119,7 @@ void GlStageBuffer::bind()
glBindVertexArray(mVao);
mGpuBuffer->bind(GlGpuBuffer::Target::ARRAY_BUFFER);
mGpuBuffer->bind(GlGpuBuffer::Target::ELEMENT_ARRAY_BUFFER);
mGpuBuffer->bind(GlGpuBuffer::Target::UNIFORM_BUFFER);
}
void GlStageBuffer::unbind()
@ -109,4 +127,27 @@ void GlStageBuffer::unbind()
glBindVertexArray(0);
mGpuBuffer->unbind(GlGpuBuffer::Target::ARRAY_BUFFER);
mGpuBuffer->unbind(GlGpuBuffer::Target::ELEMENT_ARRAY_BUFFER);
mGpuBuffer->unbind(GlGpuBuffer::Target::UNIFORM_BUFFER);
}
GLuint GlStageBuffer::getBufferId()
{
return mGpuBuffer->getBufferId();
}
void GlStageBuffer::alignOffset()
{
uint32_t alignment = _getGpuBufferAlign();
if (mStageBuffer.count % alignment == 0) return;
uint32_t offset = alignment - mStageBuffer.count % alignment;
if (mStageBuffer.count + offset > mStageBuffer.reserved) {
mStageBuffer.grow(max(alignment, mStageBuffer.reserved));
}
mStageBuffer.count += offset;
}

View file

@ -34,6 +34,7 @@ public:
{
ARRAY_BUFFER = GL_ARRAY_BUFFER,
ELEMENT_ARRAY_BUFFER = GL_ELEMENT_ARRAY_BUFFER,
UNIFORM_BUFFER = GL_UNIFORM_BUFFER,
};
GlGpuBuffer();
@ -41,6 +42,8 @@ public:
void updateBufferData(Target target, uint32_t size, const void* data);
void bind(Target target);
void unbind(Target target);
uint32_t getBufferId() { return mGlBufferId; }
private:
uint32_t mGlBufferId = 0;
@ -48,10 +51,10 @@ private:
class GlStageBuffer {
public:
GlStageBuffer() = default;
GlStageBuffer();
~GlStageBuffer();
uint32_t push(void* data, uint32_t size);
uint32_t push(void* data, uint32_t size, bool alignGpuOffset = false);
void flushToGPU();
@ -59,6 +62,9 @@ public:
void unbind();
GLuint getBufferId();
private:
void alignOffset();
private:
GLuint mVao = 0;
unique_ptr<GlGpuBuffer> mGpuBuffer = {};

View file

@ -87,6 +87,16 @@ int32_t GlProgram::getUniformLocation(const char* name)
return location;
}
int32_t GlProgram::getUniformBlockIndex(const char* name)
{
GL_CHECK(int32_t index = glGetUniformBlockIndex(mProgramObj, name));
return index;
}
uint32_t GlProgram::getProgramId()
{
return mProgramObj;
}
void GlProgram::setUniform1Value(int32_t location, int count, const int* values)
{

View file

@ -23,7 +23,6 @@
#ifndef _TVG_GL_PROGRAM_H_
#define _TVG_GL_PROGRAM_H_
#include <map>
#include "tvgGlShader.h"
class GlProgram
@ -37,6 +36,8 @@ public:
static void unload();
int32_t getAttributeLocation(const char* name);
int32_t getUniformLocation(const char* name);
int32_t getUniformBlockIndex(const char* name);
uint32_t getProgramId();
void setUniform1Value(int32_t location, int count, const int* values);
void setUniform2Value(int32_t location, int count, const int* values);
void setUniform3Value(int32_t location, int count, const int* values);

View file

@ -1,113 +0,0 @@
/*
* Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "tvgGlPropertyInterface.h"
/************************************************************************/
/* Internal Class Implementation */
/************************************************************************/
VertexProperty PropertyInterface::mEmptyProperty;
/************************************************************************/
/* External Class Implementation */
/************************************************************************/
VertexProperty& PropertyInterface::addProperty(GlRenderTask* rTask, std::shared_ptr<GlProgram> prog, std::string name, uint32_t propFormatSize, VertexProperty::PropertyType propType, VertexProperty::DataType dataType)
{
std::map<int32_t, VertexProperty>* vertexProperty = nullptr;
int32_t id;
switch (propType) {
case VertexProperty::PropertyType::ATTRIBUTE: {
id = prog->getAttributeLocation(name.c_str());
vertexProperty = &rTask->getAttributeVertexProperty();
break;
}
case VertexProperty::PropertyType::UNIFORM: {
id = prog->getUniformLocation(name.c_str());
vertexProperty = &rTask->getUniformVertexProperty();
break;
}
default: break;
}
if (id != -1)
{
VertexProperty property = { id, name, propType, dataType };
property.propertyValues.setStride(propFormatSize);
if (vertexProperty)
{
(*vertexProperty)[id] = property;
return (*vertexProperty)[id];
}
}
return mEmptyProperty;
}
void PropertyInterface::setProperty(GlRenderTask* rTask, int32_t propId, int32_t count, float* data)
{
std::map<int32_t, VertexProperty>::iterator itr = rTask->getUniformVertexProperty().find(propId);
if (itr->second.propertyId == -1) return;
VertexProperty& prop = itr->second;
for (int i = 0; i < count; ++i) {
prop.propertyValues.set(data[i]);
}
}
int32_t PropertyInterface::getPropertyId(GlRenderTask* rTask, std::string name)
{
std::map<int32_t, VertexProperty>& vertexProperty = rTask->getUniformVertexProperty();
for (auto& property : vertexProperty) {
if (property.second.propertyName == name) return property.second.propertyId;
}
return -1;
}
VertexProperty& PropertyInterface::getProperty(GlRenderTask* rTask, std::string name)
{
std::map<int32_t, VertexProperty>& vertexProperty = rTask->getUniformVertexProperty();
for (auto& property : vertexProperty) {
if (property.second.propertyName == name) return property.second;
}
return mEmptyProperty;
}
VertexProperty& PropertyInterface::getProperty(GlRenderTask* rTask, int32_t propId)
{
std::map<int32_t, VertexProperty>& vertexProperty = rTask->getUniformVertexProperty();
if (vertexProperty.find(propId) != vertexProperty.end()) return vertexProperty[propId];
return mEmptyProperty;
}
void PropertyInterface::clearData(GlRenderTask* rTask)
{
std::map<int32_t, VertexProperty>& vertexProperty = rTask->getUniformVertexProperty();
for (auto& prop : vertexProperty) {
prop.second.propertyValues.clear();
}
}

View file

@ -1,89 +0,0 @@
/*
* Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _TVG_GL_PROPERTY_INTERFACE_H_
#define _TVG_GL_PROPERTY_INTERFACE_H_
#include "tvgGlRenderTask.h"
#define ADD_ATTRIBUTE_PROPERTY(var, rtask, prog, varName, formatSize, location) \
var = &PropertyInterface::addProperty(rtask, prog, varName, formatSize, VertexProperty::PropertyType::ATTRIBUTE); \
if (var->propertyId != -1) \
location = var->propertyId
#define ADD_UNIFORM_PROPERTY(var, rtask, prog, varName, formatSize, location) \
var = &PropertyInterface::addProperty(rtask, prog, varName, formatSize, VertexProperty::PropertyType::UNIFORM); \
if (var->propertyId != -1) \
location = var->propertyId
#define ADD_UNIFORM_PROPERTY_2(var, rtask, prog, varName, formatSize, location, datatype) \
var = &PropertyInterface::addProperty(rtask, prog, varName, formatSize, VertexProperty::PropertyType::UNIFORM, datatype); \
if (var->propertyId != -1) \
location = var->propertyId
#define FORMAT_SIZE_FLOAT 1
#define FORMAT_SIZE_VEC_2 2
#define FORMAT_SIZE_VEC_3 3
#define FORMAT_SIZE_VEC_4 4
#define FORMAT_SIZE_MAT_4x4 16
class PropertyInterface
{
public:
static VertexProperty& addProperty(GlRenderTask* rTask, std::shared_ptr<GlProgram> prog, std::string name, uint32_t propFormatSize, VertexProperty::PropertyType propType, VertexProperty::DataType dataType = VertexProperty::DataType::FLOAT);
template<typename... Args>
static void setProperty(GlRenderTask* rTask, std::string name, float first, Args... args)
{
VertexProperty& prop = getProperty(rTask, name);
if (prop.propertyId == -1)
{
return;
}
setProperty(prop.propertyId, first, args...);
}
template<typename... Args>
static void setProperty(GlRenderTask* rTask, int32_t propId, float first, Args... args)
{
std::map<int32_t, VertexProperty>::iterator itr = rTask->getUniformVertexProperty().find(propId);
if (itr->second.propertyId == -1)
{
return;
}
VertexProperty& prop = itr->second;
prop.propertyValues.set(first, args...);
}
static void setProperty(GlRenderTask* rTask, int32_t propId, int32_t count, float* data);
static int32_t getPropertyId(GlRenderTask* rTask, std::string name);
static VertexProperty& getProperty(GlRenderTask* rTask, std::string name);
static VertexProperty& getProperty(GlRenderTask* rTask, int32_t propId);
static void clearData(GlRenderTask* rTask);
private:
PropertyInterface() {}
static VertexProperty mEmptyProperty;
};
#endif /* _TVG_GL_PROPERTY_INTERFACE_H_ */

View file

@ -21,268 +21,62 @@
*/
#include "tvgGlRenderTask.h"
#include "tvgGlShaderSrc.h"
#include "tvgGlPropertyInterface.h"
#include "tvgGlProgram.h"
/************************************************************************/
/* External Class Implementation */
/************************************************************************/
GlRenderTask::GlRenderTask(RenderTypes renderType, shared_ptr<GlShader> shader)
{
mRenderType = renderType;
mProgram = GlProgram::gen(shader);
load();
VertexProperty* prop = nullptr;
// now location is specified directly in shader
mLocVertexAttribute = 0;
ADD_UNIFORM_PROPERTY_2(prop, this, mProgram, "uTransform", FORMAT_SIZE_MAT_4x4, mLocTransform, VertexProperty::DataType::MATRIX);
}
GlRenderTask::RenderTypes GlRenderTask::getRenderType()
{
return mRenderType;
}
void GlRenderTask::load()
void GlRenderTask::run()
{
// bind shader
mProgram->load();
// setup attribute layout
for (uint32_t i = 0; i < mVertexLayout.count; i++) {
const auto &layout = mVertexLayout[i];
GL_CHECK(glEnableVertexAttribArray(layout.index));
GL_CHECK(glVertexAttribPointer(layout.index, layout.size, GL_FLOAT,
GL_FALSE, layout.stride,
reinterpret_cast<void *>(layout.offset)));
}
// binding uniforms
for (uint32_t i = 0; i < mBindingResources.count; i++) {
const auto& binding = mBindingResources[i];
if (binding.type == GlBindingType::kTexture) {
GL_CHECK(glActiveTexture(GL_TEXTURE0 + binding.bindPoint));
GL_CHECK(glBindTexture(GL_TEXTURE_2D, binding.gBufferId));
void GlRenderTask::unload()
mProgram->setUniform1Value(binding.location, 1, (int32_t*)&binding.bindPoint);
} else if (binding.type == GlBindingType::kUniformBuffer) {
GL_CHECK(glUniformBlockBinding(mProgram->getProgramId(), binding.location, binding.bindPoint));
GL_CHECK(glBindBufferRange(GL_UNIFORM_BUFFER, binding.bindPoint, binding.gBufferId,
binding.bufferOffset, binding.bufferRange));
}
}
GL_CHECK(glDrawElements(GL_TRIANGLES, mIndexCount, GL_UNSIGNED_INT, reinterpret_cast<void*>(mIndexOffset)));
// setup attribute layout
for (uint32_t i = 0; i < mVertexLayout.count; i++) {
const auto &layout = mVertexLayout[i];
GL_CHECK(glDisableVertexAttribArray(layout.index));
}
}
void GlRenderTask::addVertexLayout(const GlVertexLayout &layout)
{
GlProgram::unload();
mVertexLayout.push(layout);
}
std::shared_ptr<GlProgram> GlRenderTask::getProgram()
void GlRenderTask::addBindResource(const GlBindingResource &binding)
{
return mProgram;
mBindingResources.push(binding);
}
std::map<int32_t, VertexProperty>& GlRenderTask::getAttributeVertexProperty()
void GlRenderTask::setDrawRange(uint32_t offset, uint32_t count)
{
return mAttributePropertyBuffer;
}
std::map<int32_t, VertexProperty>& GlRenderTask::getUniformVertexProperty()
{
return mUniformPropertyBuffer;
}
int32_t GlRenderTask::getLocationPropertyId() const
{
return mLocVertexAttribute;
}
int32_t GlRenderTask::getTransformLocationPropertyId() const
{
return mLocTransform;
}
void GlRenderTask::setTransform(int count, float* transform)
{
if (mLocTransform != -1)
{
PropertyInterface::setProperty(this, mLocTransform, count, transform);
}
}
void GlRenderTask::uploadValues()
{
for (auto& property : mUniformPropertyBuffer)
{
PropertyValue& propertyVal = property.second.propertyValues;
switch (property.second.dataType) {
case VertexProperty::DataType::INT: {
switch (propertyVal.getStride()) {
case 1:
mProgram->setUniform1Value(property.second.propertyId, propertyVal.getCount(), (const int*)propertyVal.getData());
break;
case 2:
mProgram->setUniform2Value(property.second.propertyId, propertyVal.getCount(), (const int*)propertyVal.getData());
break;
case 3:
mProgram->setUniform3Value(property.second.propertyId, propertyVal.getCount(), (const int*)propertyVal.getData());
break;
case 4:
mProgram->setUniform4Value(property.second.propertyId, propertyVal.getCount(), (const int*)propertyVal.getData());
default: break;
}
break;
}
case VertexProperty::DataType::FLOAT: {
switch (propertyVal.getStride()) {
case 1:
mProgram->setUniform1Value(property.second.propertyId, propertyVal.getCount(), propertyVal.getData());
break;
case 2:
mProgram->setUniform2Value(property.second.propertyId, propertyVal.getCount(), propertyVal.getData());
break;
case 3:
mProgram->setUniform3Value(property.second.propertyId, propertyVal.getCount(), propertyVal.getData());
break;
case 4:
mProgram->setUniform4Value(property.second.propertyId, propertyVal.getCount(), propertyVal.getData());
default: break;
}
break;
}
case VertexProperty::DataType::MATRIX: {
mProgram->setUniform4x4Value(property.second.propertyId, propertyVal.getCount(), propertyVal.getData());
break;
}
}
}
}
std::shared_ptr<GlColorRenderTask> GlColorRenderTask::gen()
{
return std::make_shared<GlColorRenderTask>();
}
GlColorRenderTask::GlColorRenderTask()
:GlRenderTask(GlRenderTask::RenderTypes::RT_Color, GlShader::gen(COLOR_VERT_SHADER, COLOR_FRAG_SHADER))
{
VertexProperty* prop = nullptr;
ADD_UNIFORM_PROPERTY(prop, this, getProgram(), "uColor", FORMAT_SIZE_VEC_4, mLocColor);
}
void GlColorRenderTask::setColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
{
if (mLocColor != -1)
{
PropertyInterface::setProperty(this, mLocColor, r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f);
}
}
GlGradientRenderTask::GlGradientRenderTask(GlRenderTask::RenderTypes renderType, std::shared_ptr<GlShader> shader)
:GlRenderTask(renderType, shader)
{
VertexProperty* prop = nullptr;
ADD_UNIFORM_PROPERTY(prop, this, getProgram(), "noise_level", FORMAT_SIZE_FLOAT, mLocNoise);
ADD_UNIFORM_PROPERTY(prop, this, getProgram(), "nStops", FORMAT_SIZE_FLOAT, mLocStopCnt);
ADD_UNIFORM_PROPERTY(prop, this, getProgram(), "stopPoints", FORMAT_SIZE_FLOAT, mLocStops);
ADD_UNIFORM_PROPERTY(prop, this, getProgram(), "stopColors", FORMAT_SIZE_VEC_4, mLocStopColors);
}
void GlGradientRenderTask::setNoise(float noise)
{
if (mLocNoise != -1)
{
PropertyInterface::setProperty(this, mLocNoise, noise);
}
}
void GlGradientRenderTask::setStopCount(int32_t count)
{
if (mLocStopCnt != -1)
{
PropertyInterface::setProperty(this, mLocStopCnt, (float)count);
}
}
void GlGradientRenderTask::setStopColor(int index, float stopVal, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
{
if (index < MAX_GRADIENT_STOPS && mLocStops != -1 && mLocStopColors != -1)
{
PropertyInterface::setProperty(this, mLocStops, stopVal);
PropertyInterface::setProperty(this, mLocStopColors, r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f);
}
}
std::shared_ptr<GlLinearGradientRenderTask> GlLinearGradientRenderTask::gen()
{
return std::make_shared<GlLinearGradientRenderTask>();
}
GlLinearGradientRenderTask::GlLinearGradientRenderTask()
:GlGradientRenderTask(GlRenderTask::RenderTypes::RT_LinGradient, GlShader::gen(GRADIENT_VERT_SHADER, LINEAR_GRADIENT_FRAG_SHADER))
{
VertexProperty* prop = nullptr;
ADD_UNIFORM_PROPERTY(prop, this, getProgram(), "gradStartPos", FORMAT_SIZE_VEC_2, mLocStartPos);
ADD_UNIFORM_PROPERTY(prop, this, getProgram(), "gradEndPos", FORMAT_SIZE_VEC_2, mLocEndPos);
}
void GlLinearGradientRenderTask::setStartPosition(float posX, float posY)
{
if (mLocStartPos != -1)
{
PropertyInterface::setProperty(this, mLocStartPos, posX, posY);
}
}
void GlLinearGradientRenderTask::setEndPosition(float posX, float posY)
{
if (mLocEndPos != -1)
{
PropertyInterface::setProperty(this, mLocEndPos, posX, posY);
}
}
std::shared_ptr<GlRadialGradientRenderTask> GlRadialGradientRenderTask::gen()
{
return std::make_shared<GlRadialGradientRenderTask>();
}
GlRadialGradientRenderTask::GlRadialGradientRenderTask()
:GlGradientRenderTask(GlRenderTask::RenderTypes::RT_RadGradient, GlShader::gen(GRADIENT_VERT_SHADER, RADIAL_GRADIENT_FRAG_SHADER))
{
VertexProperty* prop = nullptr;
ADD_UNIFORM_PROPERTY(prop, this, getProgram(), "gradStartPos", FORMAT_SIZE_VEC_2, mLocStartPos);
ADD_UNIFORM_PROPERTY(prop, this, getProgram(), "stRadius", FORMAT_SIZE_FLOAT, mLocStRadius);
}
GlRadialGradientRenderTask::~GlRadialGradientRenderTask()
{
}
void GlRadialGradientRenderTask::setStartPosition(float posX, float posY)
{
if (mLocStartPos != -1)
{
PropertyInterface::setProperty(this, mLocStartPos, posX, posY);
}
}
void GlRadialGradientRenderTask::setStartRadius(float radius)
{
if (mLocStRadius != -1)
{
PropertyInterface::setProperty(this, mLocStRadius, radius);
}
}
void GlRadialGradientRenderTask::setEndRadius(float radius)
{
if (mLocEdRadius != -1)
{
PropertyInterface::setProperty(this, mLocEdRadius, radius);
}
mIndexOffset = offset;
mIndexCount = count;
}

View file

@ -23,102 +23,72 @@
#ifndef _TVG_GL_RENDER_TASK_H_
#define _TVG_GL_RENDER_TASK_H_
#include "tvgGlRendererProperties.h"
#include "tvgGlCommon.h"
#include "tvgGlProgram.h"
struct GlVertexLayout
{
uint32_t index;
uint32_t size;
uint32_t stride;
size_t offset;
};
enum class GlBindingType
{
kUniformBuffer,
kTexture,
};
struct GlBindingResource
{
GlBindingType type;
/**
* Binding point index.
* Can be a uniform location for a texture
* Can be a uniform buffer binding index for a uniform block
*/
uint32_t bindPoint = {};
uint32_t location = {};
GLuint gBufferId = {};
uint32_t bufferOffset = {};
uint32_t bufferRange = {};
GlBindingResource() = default;
GlBindingResource(uint32_t index, uint32_t location, uint32_t bufferId, uint32_t offset, uint32_t range)
: type(GlBindingType::kUniformBuffer), bindPoint(index), location(location), gBufferId(bufferId), bufferOffset(offset), bufferRange(range)
{
}
GlBindingResource(uint32_t bindPoint, uint32_t texId, uint32_t location)
: type(GlBindingType::kTexture), bindPoint(bindPoint), location(location), gBufferId(texId)
{
}
};
#define MAX_GRADIENT_STOPS 4
class GlRenderTask
{
public:
enum RenderTypes
{
RT_Color = 0,
RT_LinGradient,
RT_RadGradient,
GlRenderTask(GlProgram* program): mProgram(program) {}
~GlRenderTask() = default;
RT_None,
};
void run();
GlRenderTask(RenderTypes renderType, std::shared_ptr<GlShader> shader);
RenderTypes getRenderType();
void load();
static void unload();
std::shared_ptr<GlProgram> getProgram();
std::map<int32_t, VertexProperty>& getAttributeVertexProperty();
std::map<int32_t, VertexProperty>& getUniformVertexProperty();
int32_t getLocationPropertyId() const;
int32_t getTransformLocationPropertyId() const;
void setTransform(int count, float* transform_matrix);
void uploadValues();
void addVertexLayout(const GlVertexLayout& layout);
void addBindResource(const GlBindingResource& binding);
void setDrawRange(uint32_t offset, uint32_t count);
GlProgram* getProgram() { return mProgram; }
private:
RenderTypes mRenderType;
std::shared_ptr<GlProgram> mProgram;
std::map<int32_t, VertexProperty> mAttributePropertyBuffer;
std::map<int32_t, VertexProperty> mUniformPropertyBuffer;
int32_t mLocVertexAttribute = -1;
int32_t mLocTransform = -1;
GlProgram* mProgram;
uint32_t mIndexOffset = {};
uint32_t mIndexCount = {};
Array<GlVertexLayout> mVertexLayout = {};
Array<GlBindingResource> mBindingResources = {};
};
class GlColorRenderTask : public GlRenderTask
{
public:
static std::shared_ptr<GlColorRenderTask> gen();
GlColorRenderTask();
void setColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a);
private:
int32_t mLocColor = -1;
};
class GlGradientRenderTask : public GlRenderTask
{
public:
GlGradientRenderTask(GlRenderTask::RenderTypes renderType, std::shared_ptr<GlShader> shader);
void setPrimitveSize(float width, float height);
void setCanvasSize(float width, float height);
void setNoise(float noise);
void setStopCount(int32_t count);
void setStopColor(int index, float stopVal, uint8_t r, uint8_t g, uint8_t b, uint8_t a);
int32_t getTransformLocationPropertyId() const;
private:
int32_t mLocNoise = -1;
int32_t mLocStopCnt = -1;
int32_t mLocStops = -1;
int32_t mLocStopColors = -1;
};
class GlLinearGradientRenderTask : public GlGradientRenderTask
{
public:
static std::shared_ptr<GlLinearGradientRenderTask> gen();
GlLinearGradientRenderTask();
void setStartPosition(float posX, float posY);
void setEndPosition(float posX, float posY);
private:
int32_t mLocStartPos = -1;
int32_t mLocEndPos = -1;
};
class GlRadialGradientRenderTask : public GlGradientRenderTask
{
public:
static std::shared_ptr<GlRadialGradientRenderTask> gen();
GlRadialGradientRenderTask();
~GlRadialGradientRenderTask();
void setStartPosition(float posX, float posY);
void setStartRadius(float radius);
void setEndRadius(float radius);
private:
int32_t mLocStartPos = -1;
int32_t mLocStRadius = -1;
int32_t mLocEdRadius = -1;
};
#endif /* _TVG_GL_RENDER_TASK_H_ */

View file

@ -23,7 +23,9 @@
#include "tvgGlRenderer.h"
#include "tvgGlGpuBuffer.h"
#include "tvgGlGeometry.h"
#include "tvgGlPropertyInterface.h"
#include "tvgGlRenderTask.h"
#include "tvgGlProgram.h"
#include "tvgGlShaderSrc.h"
/************************************************************************/
/* Internal Class Implementation */
@ -67,8 +69,22 @@ bool GlRenderer::target(TVG_UNUSED uint32_t* buffer, uint32_t stride, uint32_t w
bool GlRenderer::sync()
{
GL_CHECK(glFinish());
GlRenderTask::unload();
mGpuBuffer->flushToGPU();
// Blend function for straight alpha
GL_CHECK(glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
GL_CHECK(glEnable(GL_BLEND));
mGpuBuffer->bind();
for(auto& task: mRenderTasks) {
task->run();
}
mGpuBuffer->unbind();
mRenderTasks.clear();
return true;
}
@ -81,19 +97,10 @@ RenderRegion GlRenderer::region(TVG_UNUSED RenderData data)
bool GlRenderer::preRender()
{
if (mRenderTasks.size() == 0)
if (mPrograms.size() == 0)
{
initShaders();
}
GlRenderTask::unload();
mGpuBuffer->flushToGPU();
// Blend function for straight alpha
GL_CHECK(glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
GL_CHECK(glEnable(GL_BLEND));
mGpuBuffer->bind();
return true;
}
@ -101,8 +108,6 @@ bool GlRenderer::preRender()
bool GlRenderer::postRender()
{
mGpuBuffer->unbind();
return true;
}
@ -243,7 +248,7 @@ RenderData GlRenderer::prepare(const RenderShape& rshape, RenderData data, const
if (sdata->updateFlag & (RenderUpdateFlag::Color | RenderUpdateFlag::Stroke | RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform) )
{
if (!sdata->geometry->tesselate(rshape, sdata->updateFlag, mGpuBuffer.get())) return sdata;
if (!sdata->geometry->tesselate(rshape, sdata->updateFlag)) return sdata;
}
return sdata;
}
@ -295,6 +300,9 @@ GlRenderer* GlRenderer::gen()
return new GlRenderer();
}
GlRenderer::GlRenderer() :mGpuBuffer(new GlStageBuffer), mPrograms(), mRenderTasks()
{
}
GlRenderer::~GlRenderer()
{
@ -309,30 +317,51 @@ GlRenderer::~GlRenderer()
void GlRenderer::initShaders()
{
// Solid Color Renderer
mRenderTasks.push_back(GlColorRenderTask::gen());
mPrograms.push_back(make_unique<GlProgram>(GlShader::gen(COLOR_VERT_SHADER, COLOR_FRAG_SHADER)));
// Linear Gradient Renderer
mRenderTasks.push_back(GlLinearGradientRenderTask::gen());
mPrograms.push_back(make_unique<GlProgram>(GlShader::gen(GRADIENT_VERT_SHADER, LINEAR_GRADIENT_FRAG_SHADER)));
// Radial Gradient Renderer
mRenderTasks.push_back(GlRadialGradientRenderTask::gen());
mPrograms.push_back(make_unique<GlProgram>(GlShader::gen(GRADIENT_VERT_SHADER, RADIAL_GRADIENT_FRAG_SHADER)));
}
void GlRenderer::drawPrimitive(GlShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a, RenderUpdateFlag flag)
{
GlColorRenderTask* renderTask = static_cast<GlColorRenderTask*>(mRenderTasks[GlRenderTask::RenderTypes::RT_Color].get());
assert(renderTask);
renderTask->load();
float* matrix = sdata.geometry->getTransforMatrix();
PropertyInterface::clearData(renderTask);
renderTask->setColor(r, g, b, a);
renderTask->setTransform(FORMAT_SIZE_MAT_4x4, matrix);
int32_t vertexLoc = renderTask->getLocationPropertyId();
renderTask->uploadValues();
sdata.geometry->draw(vertexLoc, flag);
sdata.geometry->disableVertex(vertexLoc);
auto task = make_unique<GlRenderTask>(mPrograms[RT_Color].get());
if (!sdata.geometry->draw(task.get(), mGpuBuffer.get(), flag)) return;
// matrix buffer
{
auto matrix = sdata.geometry->getTransforMatrix();
uint32_t loc = task->getProgram()->getUniformBlockIndex("Matrix");
task->addBindResource(GlBindingResource{
0,
loc,
mGpuBuffer->getBufferId(),
mGpuBuffer->push(matrix, 16 * sizeof(float), true),
16 * sizeof(float),
});
}
// color
{
float color[4] = {r / 255.f, g / 255.f, b / 255.f, a / 255.f};
uint32_t loc = task->getProgram()->getUniformBlockIndex("ColorInfo");
task->addBindResource(GlBindingResource{
1,
loc,
mGpuBuffer->getBufferId(),
mGpuBuffer->push(color, 4 * sizeof(float), true),
4 * sizeof(float),
});
}
mRenderTasks.emplace_back(std::move(task));
}
@ -342,50 +371,90 @@ void GlRenderer::drawPrimitive(GlShape& sdata, const Fill* fill, RenderUpdateFla
auto stopCnt = fill->colorStops(&stops);
if (stopCnt < 2) return;
GlGradientRenderTask* rTask = nullptr;
unique_ptr<GlRenderTask> task;
if (fill->identifier() == TVG_CLASS_ID_LINEAR) {
task = make_unique<GlRenderTask>(mPrograms[RT_LinGradient].get());
} else if (fill->identifier() == TVG_CLASS_ID_RADIAL) {
task = make_unique<GlRenderTask>(mPrograms[RT_RadGradient].get());
} else {
return;
}
if (!sdata.geometry->draw(task.get(), mGpuBuffer.get(), flag)) return;
// matrix buffer
{
auto matrix = sdata.geometry->getTransforMatrix();
uint32_t loc = task->getProgram()->getUniformBlockIndex("Matrix");
switch (fill->identifier()) {
case TVG_CLASS_ID_LINEAR: {
float x1, y1, x2, y2;
GlLinearGradientRenderTask *renderTask = static_cast<GlLinearGradientRenderTask*>(mRenderTasks[GlRenderTask::RenderTypes::RT_LinGradient].get());
assert(renderTask);
rTask = renderTask;
renderTask->load();
PropertyInterface::clearData(renderTask);
const LinearGradient* grad = static_cast<const LinearGradient*>(fill);
grad->linear(&x1, &y1, &x2, &y2);
renderTask->setStartPosition(x1, y1);
renderTask->setEndPosition(x2, y2);
break;
task->addBindResource(GlBindingResource{
0,
loc,
mGpuBuffer->getBufferId(),
mGpuBuffer->push(matrix, 16 * sizeof(float), true),
16 * sizeof(float),
});
}
case TVG_CLASS_ID_RADIAL: {
float x1, y1, r1;
GlRadialGradientRenderTask *renderTask = static_cast<GlRadialGradientRenderTask*>(mRenderTasks[GlRenderTask::RenderTypes::RT_RadGradient].get());
assert(renderTask);
rTask = renderTask;
renderTask->load();
PropertyInterface::clearData(renderTask);
const RadialGradient* grad = static_cast<const RadialGradient*>(fill);
grad->radial(&x1, &y1, &r1);
renderTask->setStartPosition(x1, y1);
renderTask->setStartRadius(r1);
break;
}
}
if (rTask) {
auto vertexLoc = rTask->getLocationPropertyId();
rTask->setNoise(NOISE_LEVEL);
rTask->setStopCount((int)stopCnt);
rTask->setTransform(FORMAT_SIZE_MAT_4x4, matrix);
// gradient block
{
GlBindingResource gradientBinding{};
uint32_t loc = task->getProgram()->getUniformBlockIndex("GradientInfo");
if (fill->identifier() == TVG_CLASS_ID_LINEAR) {
auto linearFill = static_cast<const LinearGradient*>(fill);
GlLinearGradientBlock gradientBlock;
gradientBlock.nStops[0] = stopCnt * 1.f;
gradientBlock.nStops[1] = NOISE_LEVEL;
for (uint32_t i = 0; i < stopCnt; ++i) {
rTask->setStopColor(i, stops[i].offset, stops[i].r, stops[i].g, stops[i].b, stops[i].a);
gradientBlock.stopPoints[i] = stops[i].offset;
gradientBlock.stopColors[i * 4 + 0] = stops[i].r / 255.f;
gradientBlock.stopColors[i * 4 + 1] = stops[i].g / 255.f;
gradientBlock.stopColors[i * 4 + 2] = stops[i].b / 255.f;
gradientBlock.stopColors[i * 4 + 3] = stops[i].a / 255.f;
}
rTask->uploadValues();
sdata.geometry->draw(vertexLoc, flag);
sdata.geometry->disableVertex(vertexLoc);
}
linearFill->linear(&gradientBlock.startPos[0], &gradientBlock.startPos[1], &gradientBlock.stopPos[0], &gradientBlock.stopPos[1]);
gradientBinding = GlBindingResource{
1,
loc,
mGpuBuffer->getBufferId(),
mGpuBuffer->push(&gradientBlock, sizeof(GlLinearGradientBlock), true),
sizeof(GlLinearGradientBlock),
};
} else {
auto radialFill = static_cast<const RadialGradient*>(fill);
GlRadialGradientBlock gradientBlock;
gradientBlock.nStops[0] = stopCnt * 1.f;
gradientBlock.nStops[1] = NOISE_LEVEL;
for (uint32_t i = 0; i < stopCnt; ++i) {
gradientBlock.stopPoints[i] = stops[i].offset;
gradientBlock.stopColors[i * 4 + 0] = stops[i].r / 255.f;
gradientBlock.stopColors[i * 4 + 1] = stops[i].g / 255.f;
gradientBlock.stopColors[i * 4 + 2] = stops[i].b / 255.f;
gradientBlock.stopColors[i * 4 + 3] = stops[i].a / 255.f;
}
radialFill->radial(&gradientBlock.centerPos[0], &gradientBlock.centerPos[1], &gradientBlock.radius[0]);
gradientBinding = GlBindingResource{
1,
loc,
mGpuBuffer->getBufferId(),
mGpuBuffer->push(&gradientBlock, sizeof(GlRadialGradientBlock), true),
sizeof(GlRadialGradientBlock),
};
}
task->addBindResource(gradientBinding);
}
mRenderTasks.emplace_back(std::move(task));
}

View file

@ -23,12 +23,23 @@
#ifndef _TVG_GL_RENDERER_H_
#define _TVG_GL_RENDERER_H_
#include <vector>
#include "tvgGlRenderTask.h"
#include "tvgGlGpuBuffer.h"
class GlRenderer : public RenderMethod
{
public:
enum RenderTypes
{
RT_Color = 0,
RT_LinGradient,
RT_RadGradient,
RT_None,
};
Surface surface = {nullptr, 0, 0, 0, ColorSpace::Unsupported, true};
RenderData prepare(const RenderShape& rshape, RenderData data, const RenderTransform* transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag flags, bool clipper) override;
@ -59,15 +70,16 @@ public:
static int term();
private:
GlRenderer(): mGpuBuffer(new GlStageBuffer) {};
GlRenderer();
~GlRenderer();
void initShaders();
void drawPrimitive(GlShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a, RenderUpdateFlag flag);
void drawPrimitive(GlShape& sdata, const Fill* fill, RenderUpdateFlag flag);
vector<shared_ptr<GlRenderTask>> mRenderTasks;
std::unique_ptr<GlStageBuffer> mGpuBuffer;
vector<std::unique_ptr<GlProgram>> mPrograms;
vector<std::unique_ptr<GlRenderTask>> mRenderTasks;
};
#endif /* _TVG_GL_RENDERER_H_ */

View file

@ -1,111 +0,0 @@
/*
* Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _TVG_GL_RENDER_PROPERTIES_H_
#define _TVG_GL_RENDER_PROPERTIES_H_
#include <vector>
#include "tvgGlCommon.h"
#include "tvgGlProgram.h"
class PropertyValue
{
public:
void setStride(uint32_t s)
{
stride = s;
if (values.capacity() == values.size())
{
values.reserve(values.size() + stride);
}
}
uint32_t getStride() const
{
return stride;
}
uint32_t getSize() const
{
return values.size();
}
uint32_t getCount() const
{
return (values.size() / stride);
}
void clear()
{
values.clear();
}
const float* getData()
{
return values.data();
}
void set(float v)
{
values.push_back(v);
}
template<typename... Args>
void set(float first, Args... args)
{
if (values.capacity() == values.size())
{
values.reserve(values.size() + stride);
}
set(first);
set(args...);
}
private:
std::vector<float> values;
uint32_t stride = 0;
};
struct VertexProperty
{
public:
enum class DataType
{
INT = 0,
FLOAT,
MATRIX
};
enum class PropertyType
{
ATTRIBUTE = 0,
UNIFORM
};
int32_t propertyId = -1;
std::string propertyName = "";
PropertyType propType = PropertyType::UNIFORM;
DataType dataType = DataType::FLOAT;
PropertyValue propertyValues;
};
#endif /* _TVG_GL_RENDER_PROPERTIES_H_ */

View file

@ -27,20 +27,26 @@
const char* COLOR_VERT_SHADER = TVG_COMPOSE_SHADER(
layout(location = 0) in vec3 aLocation; \n
uniform mat4 uTransform; \n
layout(std140) uniform Matrix { \n
mat4 transform; \n
} uMatrix; \n
out float vOpacity; \n
void main() \n
{ \n
gl_Position = uTransform * vec4(aLocation.xy, 0.0, 1.0); \n
gl_Position = \n
uMatrix.transform * vec4(aLocation.xy, 0.0, 1.0); \n
vOpacity = aLocation.z; \n
});
const char* COLOR_FRAG_SHADER = TVG_COMPOSE_SHADER(
uniform vec4 uColor; \n
layout(std140) uniform ColorInfo { \n
vec4 solidColor; \n
} uColorInfo; \n
in float vOpacity; \n
out vec4 FragColor; \n
void main() \n
{ \n
vec4 uColor = uColorInfo.solidColor; \n
FragColor = vec4(uColor.xyz, uColor.w*vOpacity); \n
});
@ -48,22 +54,20 @@ const char* GRADIENT_VERT_SHADER = TVG_COMPOSE_SHADER(
layout(location = 0) in vec3 aLocation; \n
out float vOpacity; \n
out vec2 vPos; \n
uniform mat4 uTransform; \n
layout(std140) uniform Matrix { \n
mat4 transform; \n
} uMatrix; \n
\n
void main() \n
{ \n
gl_Position = uTransform * vec4(aLocation.xy, 0.0, 1.0); \n
gl_Position = uMatrix.transform * vec4(aLocation.xy, 0.0, 1.0); \n
vOpacity = aLocation.z; \n
vPos = aLocation.xy; \n
});
std::string STR_GRADIENT_FRAG_COMMON_VARIABLES = TVG_COMPOSE_SHADER( \n
std::string STR_GRADIENT_FRAG_COMMON_VARIABLES = TVG_COMPOSE_SHADER(
const int MAX_STOP_COUNT = 4; \n
uniform float nStops; \n
uniform float noise_level; \n
uniform float stopPoints[MAX_STOP_COUNT]; \n
uniform vec4 stopColors[MAX_STOP_COUNT]; \n
in vec2 vPos; \n
in float vOpacity; \n
);
@ -80,23 +84,26 @@ vec4 gradient(float t)
{ \n
vec4 col = vec4(0.0); \n
int i = 0; \n
int count = int(nStops); \n
if (t <= stopPoints[0]) \n
int count = int(uGradientInfo.nStops[0]); \n
if (t <= uGradientInfo.stopPoints[0]) \n
{ \n
col += stopColors[0]; \n
col += uGradientInfo.stopColors[0]; \n
} \n
else if (t >= stopPoints[count - 1]) \n
else if (t >= uGradientInfo.stopPoints[count - 1]) \n
{ \n
col += stopColors[count - 1]; \n
col += uGradientInfo.stopColors[count - 1]; \n
} \n
else \n
{ \n
for (i = 0; i < count - 1; ++i) \n
{ \n
if (t > stopPoints[i] && t < stopPoints[i + 1]) \n
if (t > uGradientInfo.stopPoints[i] && t < uGradientInfo.stopPoints[i + 1]) \n
{ \n
col += (stopColors[i] * (1. - gradientStep(stopPoints[i], stopPoints[i + 1], t))); \n
col += (stopColors[i + 1] * gradientStep(stopPoints[i], stopPoints[i + 1], t)); \n
col += (uGradientInfo.stopColors[i] * \n
(1. - gradientStep(uGradientInfo.stopPoints[i], \n
uGradientInfo.stopPoints[i + 1], t))); \n
col += (uGradientInfo.stopColors[i + 1] * \n
gradientStep(uGradientInfo.stopPoints[i], uGradientInfo.stopPoints[i + 1], t)); \n
break; \n
} \n
} \n
@ -113,8 +120,13 @@ vec3 ScreenSpaceDither(vec2 vScreenPos)
});
std::string STR_LINEAR_GRADIENT_VARIABLES = TVG_COMPOSE_SHADER(
uniform vec2 gradStartPos; \n
uniform vec2 gradEndPos; \n
layout(std140) uniform GradientInfo { \n
vec4 nStops; \n
vec2 gradStartPos; \n
vec2 gradEndPos; \n
vec4 stopPoints; \n
vec4 stopColors[MAX_STOP_COUNT]; \n
} uGradientInfo ; \n
);
std::string STR_LINEAR_GRADIENT_MAIN = TVG_COMPOSE_SHADER(
@ -122,8 +134,8 @@ out vec4 FragColor;
void main() \n
{ \n
vec2 pos = vPos; \n
vec2 st = gradStartPos; \n
vec2 ed = gradEndPos; \n
vec2 st = uGradientInfo.gradStartPos; \n
vec2 ed = uGradientInfo.gradEndPos; \n
\n
vec2 ba = ed - st; \n
\n
@ -134,14 +146,19 @@ void main()
\n
vec4 color = gradient(t); \n
\n
vec3 noise = 8.0 * noise_level * ScreenSpaceDither(pos); \n
vec3 noise = 8.0 * uGradientInfo.nStops[1] * ScreenSpaceDither(pos); \n
vec4 finalCol = vec4(color.xyz + noise, color.w); \n
FragColor = vec4(finalCol.xyz, finalCol.w* vOpacity); \n
});
std::string STR_RADIAL_GRADIENT_VARIABLES = TVG_COMPOSE_SHADER(
uniform vec2 gradStartPos; \n
uniform float stRadius; \n
layout(std140) uniform GradientInfo { \n
vec4 nStops; \n
vec2 centerPos; \n
vec2 radius; \n
vec4 stopPoints; \n
vec4 stopColors[MAX_STOP_COUNT]; \n
} uGradientInfo ; \n
);
std::string STR_RADIAL_GRADIENT_MAIN = TVG_COMPOSE_SHADER(
@ -150,8 +167,8 @@ void main()
{ \n
vec2 pos = vPos; \n
\n
float ba = stRadius; \n
float d = distance(gradStartPos, pos); \n
float ba = uGradientInfo.radius.x; \n
float d = distance(uGradientInfo.centerPos, pos); \n
d = (d / ba); \n
\n
//float t = smoothstep(0.0, 1.0, clamp(d, 0.0, 1.0)); \n
@ -159,7 +176,7 @@ void main()
\n
vec4 color = gradient(t); \n
\n
vec3 noise = 8.0 * noise_level * ScreenSpaceDither(pos); \n
vec3 noise = 8.0 * uGradientInfo.nStops[1] * ScreenSpaceDither(pos); \n
vec4 finalCol = vec4(color.xyz + noise, color.w); \n
FragColor = vec4(finalCol.xyz, finalCol.w * vOpacity); \n
});