2d Legacy - close vulnerabilities and more debug checks
While adding more debug checks to legacy renderer, I closed 2 types of vulnerabilities: * TYPE_PRIMITIVE would previously read from uninitialized data if only specifying a single color * Other legacy draw operations would fail in debug AFTER accessing out of bounds memory rather than before Many calls to glBufferSubData are wrapped in a safe version which checks for out of bounds and exits the draw function if this is detected.
This commit is contained in:
parent
b900ec03f0
commit
3c69377f10
|
@ -32,6 +32,7 @@
|
|||
|
||||
#include "core/os/os.h"
|
||||
#include "core/project_settings.h"
|
||||
#include "drivers/gles_common/rasterizer_asserts.h"
|
||||
#include "rasterizer_scene_gles2.h"
|
||||
#include "servers/visual/visual_server_raster.h"
|
||||
|
||||
|
@ -447,11 +448,16 @@ void RasterizerCanvasBaseGLES2::_draw_polygon(const int *p_indices, int p_index_
|
|||
glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer);
|
||||
|
||||
uint32_t buffer_ofs = 0;
|
||||
uint32_t buffer_ofs_after = buffer_ofs + (sizeof(Vector2) * p_vertex_count);
|
||||
#ifdef DEBUG_ENABLED
|
||||
ERR_FAIL_COND(buffer_ofs_after > data.polygon_buffer_size);
|
||||
#endif
|
||||
|
||||
storage->buffer_orphan_and_upload(data.polygon_buffer_size, 0, sizeof(Vector2) * p_vertex_count, p_vertices, GL_ARRAY_BUFFER, _buffer_upload_usage_flag, true);
|
||||
|
||||
glEnableVertexAttribArray(VS::ARRAY_VERTEX);
|
||||
glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), NULL);
|
||||
buffer_ofs += sizeof(Vector2) * p_vertex_count;
|
||||
buffer_ofs = buffer_ofs_after;
|
||||
|
||||
if (p_singlecolor) {
|
||||
glDisableVertexAttribArray(VS::ARRAY_COLOR);
|
||||
|
@ -461,31 +467,31 @@ void RasterizerCanvasBaseGLES2::_draw_polygon(const int *p_indices, int p_index_
|
|||
glDisableVertexAttribArray(VS::ARRAY_COLOR);
|
||||
glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1);
|
||||
} else {
|
||||
glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Color) * p_vertex_count, p_colors);
|
||||
RAST_FAIL_COND(!storage->safe_buffer_sub_data(data.polygon_buffer_size, GL_ARRAY_BUFFER, buffer_ofs, sizeof(Color) * p_vertex_count, p_colors, buffer_ofs_after));
|
||||
glEnableVertexAttribArray(VS::ARRAY_COLOR);
|
||||
glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(Color), CAST_INT_TO_UCHAR_PTR(buffer_ofs));
|
||||
buffer_ofs += sizeof(Color) * p_vertex_count;
|
||||
buffer_ofs = buffer_ofs_after;
|
||||
}
|
||||
|
||||
if (p_uvs) {
|
||||
glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_uvs);
|
||||
RAST_FAIL_COND(!storage->safe_buffer_sub_data(data.polygon_buffer_size, GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_uvs, buffer_ofs_after));
|
||||
glEnableVertexAttribArray(VS::ARRAY_TEX_UV);
|
||||
glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buffer_ofs));
|
||||
buffer_ofs += sizeof(Vector2) * p_vertex_count;
|
||||
buffer_ofs = buffer_ofs_after;
|
||||
} else {
|
||||
glDisableVertexAttribArray(VS::ARRAY_TEX_UV);
|
||||
}
|
||||
|
||||
if (p_weights && p_bones) {
|
||||
glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(float) * 4 * p_vertex_count, p_weights);
|
||||
RAST_FAIL_COND(!storage->safe_buffer_sub_data(data.polygon_buffer_size, GL_ARRAY_BUFFER, buffer_ofs, sizeof(float) * 4 * p_vertex_count, p_weights, buffer_ofs_after));
|
||||
glEnableVertexAttribArray(VS::ARRAY_WEIGHTS);
|
||||
glVertexAttribPointer(VS::ARRAY_WEIGHTS, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 4, CAST_INT_TO_UCHAR_PTR(buffer_ofs));
|
||||
buffer_ofs += sizeof(float) * 4 * p_vertex_count;
|
||||
buffer_ofs = buffer_ofs_after;
|
||||
|
||||
glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(int) * 4 * p_vertex_count, p_bones);
|
||||
RAST_FAIL_COND(!storage->safe_buffer_sub_data(data.polygon_buffer_size, GL_ARRAY_BUFFER, buffer_ofs, sizeof(int) * 4 * p_vertex_count, p_bones, buffer_ofs_after));
|
||||
glEnableVertexAttribArray(VS::ARRAY_BONES);
|
||||
glVertexAttribPointer(VS::ARRAY_BONES, 4, GL_UNSIGNED_INT, GL_FALSE, sizeof(int) * 4, CAST_INT_TO_UCHAR_PTR(buffer_ofs));
|
||||
buffer_ofs += sizeof(int) * 4 * p_vertex_count;
|
||||
buffer_ofs = buffer_ofs_after;
|
||||
|
||||
} else {
|
||||
glDisableVertexAttribArray(VS::ARRAY_WEIGHTS);
|
||||
|
@ -495,10 +501,16 @@ void RasterizerCanvasBaseGLES2::_draw_polygon(const int *p_indices, int p_index_
|
|||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer);
|
||||
|
||||
if (storage->config.support_32_bits_indices) { //should check for
|
||||
#ifdef DEBUG_ENABLED
|
||||
ERR_FAIL_COND((sizeof(int) * p_index_count) > data.polygon_index_buffer_size);
|
||||
#endif
|
||||
storage->buffer_orphan_and_upload(data.polygon_index_buffer_size, 0, sizeof(int) * p_index_count, p_indices, GL_ELEMENT_ARRAY_BUFFER, _buffer_upload_usage_flag, true);
|
||||
glDrawElements(GL_TRIANGLES, p_index_count, GL_UNSIGNED_INT, 0);
|
||||
storage->info.render._2d_draw_call_count++;
|
||||
} else {
|
||||
#ifdef DEBUG_ENABLED
|
||||
ERR_FAIL_COND((sizeof(uint16_t) * p_index_count) > data.polygon_index_buffer_size);
|
||||
#endif
|
||||
uint16_t *index16 = (uint16_t *)alloca(sizeof(uint16_t) * p_index_count);
|
||||
for (int i = 0; i < p_index_count; i++) {
|
||||
index16[i] = uint16_t(p_indices[i]);
|
||||
|
@ -517,11 +529,15 @@ void RasterizerCanvasBaseGLES2::_draw_generic(GLuint p_primitive, int p_vertex_c
|
|||
glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer);
|
||||
|
||||
uint32_t buffer_ofs = 0;
|
||||
uint32_t buffer_ofs_after = buffer_ofs + (sizeof(Vector2) * p_vertex_count);
|
||||
#ifdef DEBUG_ENABLED
|
||||
ERR_FAIL_COND(buffer_ofs_after > data.polygon_buffer_size);
|
||||
#endif
|
||||
storage->buffer_orphan_and_upload(data.polygon_buffer_size, 0, sizeof(Vector2) * p_vertex_count, p_vertices, GL_ARRAY_BUFFER, _buffer_upload_usage_flag, true);
|
||||
|
||||
glEnableVertexAttribArray(VS::ARRAY_VERTEX);
|
||||
glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), NULL);
|
||||
buffer_ofs += sizeof(Vector2) * p_vertex_count;
|
||||
buffer_ofs = buffer_ofs_after;
|
||||
|
||||
if (p_singlecolor) {
|
||||
glDisableVertexAttribArray(VS::ARRAY_COLOR);
|
||||
|
@ -531,16 +547,17 @@ void RasterizerCanvasBaseGLES2::_draw_generic(GLuint p_primitive, int p_vertex_c
|
|||
glDisableVertexAttribArray(VS::ARRAY_COLOR);
|
||||
glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1);
|
||||
} else {
|
||||
glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Color) * p_vertex_count, p_colors);
|
||||
RAST_FAIL_COND(!storage->safe_buffer_sub_data(data.polygon_buffer_size, GL_ARRAY_BUFFER, buffer_ofs, sizeof(Color) * p_vertex_count, p_colors, buffer_ofs_after));
|
||||
glEnableVertexAttribArray(VS::ARRAY_COLOR);
|
||||
glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(Color), CAST_INT_TO_UCHAR_PTR(buffer_ofs));
|
||||
buffer_ofs += sizeof(Color) * p_vertex_count;
|
||||
buffer_ofs = buffer_ofs_after;
|
||||
}
|
||||
|
||||
if (p_uvs) {
|
||||
glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_uvs);
|
||||
RAST_FAIL_COND(!storage->safe_buffer_sub_data(data.polygon_buffer_size, GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_uvs, buffer_ofs_after));
|
||||
glEnableVertexAttribArray(VS::ARRAY_TEX_UV);
|
||||
glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buffer_ofs));
|
||||
buffer_ofs = buffer_ofs_after;
|
||||
} else {
|
||||
glDisableVertexAttribArray(VS::ARRAY_TEX_UV);
|
||||
}
|
||||
|
@ -556,11 +573,15 @@ void RasterizerCanvasBaseGLES2::_draw_generic_indices(GLuint p_primitive, const
|
|||
glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer);
|
||||
|
||||
uint32_t buffer_ofs = 0;
|
||||
uint32_t buffer_ofs_after = buffer_ofs + (sizeof(Vector2) * p_vertex_count);
|
||||
#ifdef DEBUG_ENABLED
|
||||
ERR_FAIL_COND(buffer_ofs_after > data.polygon_buffer_size);
|
||||
#endif
|
||||
storage->buffer_orphan_and_upload(data.polygon_buffer_size, 0, sizeof(Vector2) * p_vertex_count, p_vertices, GL_ARRAY_BUFFER, _buffer_upload_usage_flag, true);
|
||||
|
||||
glEnableVertexAttribArray(VS::ARRAY_VERTEX);
|
||||
glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), NULL);
|
||||
buffer_ofs += sizeof(Vector2) * p_vertex_count;
|
||||
buffer_ofs = buffer_ofs_after;
|
||||
|
||||
if (p_singlecolor) {
|
||||
glDisableVertexAttribArray(VS::ARRAY_COLOR);
|
||||
|
@ -570,28 +591,41 @@ void RasterizerCanvasBaseGLES2::_draw_generic_indices(GLuint p_primitive, const
|
|||
glDisableVertexAttribArray(VS::ARRAY_COLOR);
|
||||
glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1);
|
||||
} else {
|
||||
glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Color) * p_vertex_count, p_colors);
|
||||
RAST_FAIL_COND(!storage->safe_buffer_sub_data(data.polygon_buffer_size, GL_ARRAY_BUFFER, buffer_ofs, sizeof(Color) * p_vertex_count, p_colors, buffer_ofs_after));
|
||||
glEnableVertexAttribArray(VS::ARRAY_COLOR);
|
||||
glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(Color), CAST_INT_TO_UCHAR_PTR(buffer_ofs));
|
||||
buffer_ofs += sizeof(Color) * p_vertex_count;
|
||||
buffer_ofs = buffer_ofs_after;
|
||||
}
|
||||
|
||||
if (p_uvs) {
|
||||
glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_uvs);
|
||||
RAST_FAIL_COND(!storage->safe_buffer_sub_data(data.polygon_buffer_size, GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_uvs, buffer_ofs_after));
|
||||
glEnableVertexAttribArray(VS::ARRAY_TEX_UV);
|
||||
glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buffer_ofs));
|
||||
buffer_ofs += sizeof(Vector2) * p_vertex_count;
|
||||
buffer_ofs = buffer_ofs_after;
|
||||
} else {
|
||||
glDisableVertexAttribArray(VS::ARRAY_TEX_UV);
|
||||
}
|
||||
|
||||
#ifdef RASTERIZER_EXTRA_CHECKS
|
||||
// very slow, do not enable in normal use
|
||||
for (int n = 0; n < p_index_count; n++) {
|
||||
RAST_DEV_DEBUG_ASSERT(p_indices[n] < p_vertex_count);
|
||||
}
|
||||
#endif
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer);
|
||||
|
||||
if (storage->config.support_32_bits_indices) { //should check for
|
||||
#ifdef DEBUG_ENABLED
|
||||
ERR_FAIL_COND((sizeof(int) * p_index_count) > data.polygon_index_buffer_size);
|
||||
#endif
|
||||
storage->buffer_orphan_and_upload(data.polygon_index_buffer_size, 0, sizeof(int) * p_index_count, p_indices, GL_ELEMENT_ARRAY_BUFFER, _buffer_upload_usage_flag, true);
|
||||
glDrawElements(p_primitive, p_index_count, GL_UNSIGNED_INT, 0);
|
||||
storage->info.render._2d_draw_call_count++;
|
||||
} else {
|
||||
#ifdef DEBUG_ENABLED
|
||||
ERR_FAIL_COND((sizeof(uint16_t) * p_index_count) > data.polygon_index_buffer_size);
|
||||
#endif
|
||||
uint16_t *index16 = (uint16_t *)alloca(sizeof(uint16_t) * p_index_count);
|
||||
for (int i = 0; i < p_index_count; i++) {
|
||||
index16[i] = uint16_t(p_indices[i]);
|
||||
|
@ -629,6 +663,7 @@ void RasterizerCanvasBaseGLES2::_draw_gui_primitive(int p_points, const Vector2
|
|||
stride += 1;
|
||||
}
|
||||
|
||||
RAST_DEV_DEBUG_ASSERT(p_points <= 4);
|
||||
float buffer_data[(2 + 2 + 4 + 1) * 4];
|
||||
|
||||
for (int i = 0; i < p_points; i++) {
|
||||
|
@ -939,8 +974,8 @@ void RasterizerCanvasBaseGLES2::initialize() {
|
|||
{
|
||||
uint32_t poly_size = GLOBAL_DEF("rendering/limits/buffers/canvas_polygon_buffer_size_kb", 128);
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/buffers/canvas_polygon_buffer_size_kb", PropertyInfo(Variant::INT, "rendering/limits/buffers/canvas_polygon_buffer_size_kb", PROPERTY_HINT_RANGE, "0,256,1,or_greater"));
|
||||
poly_size = MAX(poly_size, 2); // minimum 2k, may still see anomalies in editor
|
||||
poly_size *= 1024;
|
||||
poly_size = MAX(poly_size, (2 + 2 + 4) * 4 * sizeof(float));
|
||||
glGenBuffers(1, &data.polygon_buffer);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, poly_size, NULL, GL_DYNAMIC_DRAW);
|
||||
|
@ -951,6 +986,7 @@ void RasterizerCanvasBaseGLES2::initialize() {
|
|||
|
||||
uint32_t index_size = GLOBAL_DEF("rendering/limits/buffers/canvas_polygon_index_buffer_size_kb", 128);
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/buffers/canvas_polygon_index_buffer_size_kb", PropertyInfo(Variant::INT, "rendering/limits/buffers/canvas_polygon_index_buffer_size_kb", PROPERTY_HINT_RANGE, "0,256,1,or_greater"));
|
||||
index_size = MAX(index_size, 2);
|
||||
index_size *= 1024; // kb
|
||||
glGenBuffers(1, &data.polygon_index_buffer);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer);
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
|
||||
#include "core/os/os.h"
|
||||
#include "core/project_settings.h"
|
||||
#include "drivers/gles_common/rasterizer_asserts.h"
|
||||
#include "rasterizer_scene_gles2.h"
|
||||
#include "servers/visual/visual_server_raster.h"
|
||||
|
||||
|
@ -1122,14 +1123,27 @@ void RasterizerCanvasGLES2::render_batches(Item::Command *const *p_commands, Ite
|
|||
state.canvas_shader.set_uniform(CanvasShaderGLES2::COLOR_TEXPIXEL_SIZE, texpixel_size);
|
||||
}
|
||||
|
||||
// we need a temporary because this must be nulled out
|
||||
// if only a single color specified
|
||||
const Color *colors = primitive->colors.ptr();
|
||||
if (primitive->colors.size() == 1 && primitive->points.size() > 1) {
|
||||
Color c = primitive->colors[0];
|
||||
glVertexAttrib4f(VS::ARRAY_COLOR, c.r, c.g, c.b, c.a);
|
||||
colors = nullptr;
|
||||
} else if (primitive->colors.empty()) {
|
||||
glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1);
|
||||
}
|
||||
#ifdef RASTERIZER_EXTRA_CHECKS
|
||||
else {
|
||||
RAST_DEV_DEBUG_ASSERT(primitive->colors.size() == primitive->points.size());
|
||||
}
|
||||
|
||||
_draw_gui_primitive(primitive->points.size(), primitive->points.ptr(), primitive->colors.ptr(), primitive->uvs.ptr());
|
||||
if (primitive->uvs.ptr()) {
|
||||
RAST_DEV_DEBUG_ASSERT(primitive->uvs.size() == primitive->points.size());
|
||||
}
|
||||
#endif
|
||||
|
||||
_draw_gui_primitive(primitive->points.size(), primitive->points.ptr(), colors, primitive->uvs.ptr());
|
||||
} break;
|
||||
|
||||
case Item::Command::TYPE_TRANSFORM: {
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
|
||||
#include "core/pool_vector.h"
|
||||
#include "core/self_list.h"
|
||||
#include "drivers/gles_common/rasterizer_asserts.h"
|
||||
#include "servers/visual/rasterizer.h"
|
||||
#include "servers/visual/shader_language.h"
|
||||
#include "shader_compiler_gles2.h"
|
||||
|
@ -1343,19 +1344,46 @@ public:
|
|||
virtual String get_video_adapter_name() const;
|
||||
virtual String get_video_adapter_vendor() const;
|
||||
|
||||
void buffer_orphan_and_upload(unsigned int p_buffer_size, unsigned int p_offset, unsigned int p_data_size, const void *p_data, GLenum p_target = GL_ARRAY_BUFFER, GLenum p_usage = GL_DYNAMIC_DRAW, bool p_optional_orphan = false);
|
||||
void buffer_orphan_and_upload(unsigned int p_buffer_size, unsigned int p_offset, unsigned int p_data_size, const void *p_data, GLenum p_target = GL_ARRAY_BUFFER, GLenum p_usage = GL_DYNAMIC_DRAW, bool p_optional_orphan = false) const;
|
||||
bool safe_buffer_sub_data(unsigned int p_total_buffer_size, GLenum p_target, unsigned int p_offset, unsigned int p_data_size, const void *p_data, unsigned int &r_offset_after) const;
|
||||
|
||||
RasterizerStorageGLES2();
|
||||
};
|
||||
|
||||
inline bool RasterizerStorageGLES2::safe_buffer_sub_data(unsigned int p_total_buffer_size, GLenum p_target, unsigned int p_offset, unsigned int p_data_size, const void *p_data, unsigned int &r_offset_after) const {
|
||||
r_offset_after = p_offset + p_data_size;
|
||||
#ifdef DEBUG_ENABLED
|
||||
// we are trying to write across the edge of the buffer
|
||||
if (r_offset_after > p_total_buffer_size)
|
||||
return false;
|
||||
#endif
|
||||
glBufferSubData(p_target, p_offset, p_data_size, p_data);
|
||||
return true;
|
||||
}
|
||||
|
||||
// standardize the orphan / upload in one place so it can be changed per platform as necessary, and avoid future
|
||||
// bugs causing pipeline stalls
|
||||
inline void RasterizerStorageGLES2::buffer_orphan_and_upload(unsigned int p_buffer_size, unsigned int p_offset, unsigned int p_data_size, const void *p_data, GLenum p_target, GLenum p_usage, bool p_optional_orphan) {
|
||||
inline void RasterizerStorageGLES2::buffer_orphan_and_upload(unsigned int p_buffer_size, unsigned int p_offset, unsigned int p_data_size, const void *p_data, GLenum p_target, GLenum p_usage, bool p_optional_orphan) const {
|
||||
// Orphan the buffer to avoid CPU/GPU sync points caused by glBufferSubData
|
||||
// Was previously #ifndef GLES_OVER_GL however this causes stalls on desktop mac also (and possibly other)
|
||||
if (!p_optional_orphan || (config.should_orphan)) {
|
||||
glBufferData(p_target, p_buffer_size, NULL, p_usage);
|
||||
#ifdef RASTERIZER_EXTRA_CHECKS
|
||||
// fill with garbage off the end of the array
|
||||
if (p_buffer_size) {
|
||||
unsigned int start = p_offset + p_data_size;
|
||||
unsigned int end = start + 1024;
|
||||
if (end < p_buffer_size) {
|
||||
uint8_t *garbage = (uint8_t *)alloca(1024);
|
||||
for (int n = 0; n < 1024; n++) {
|
||||
garbage[n] = Math::random(0, 255);
|
||||
}
|
||||
glBufferSubData(p_target, start, 1024, garbage);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
RAST_DEV_DEBUG_ASSERT((p_offset + p_data_size) <= p_buffer_size);
|
||||
glBufferSubData(p_target, p_offset, p_data_size, p_data);
|
||||
}
|
||||
|
||||
|
|
|
@ -350,16 +350,18 @@ void RasterizerCanvasBaseGLES3::_draw_polygon(const int *p_indices, int p_index_
|
|||
glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer);
|
||||
|
||||
uint32_t buffer_ofs = 0;
|
||||
uint32_t buffer_ofs_after = buffer_ofs + (sizeof(Vector2) * p_vertex_count);
|
||||
#ifdef DEBUG_ENABLED
|
||||
ERR_FAIL_COND(buffer_ofs_after > data.polygon_buffer_size);
|
||||
#endif
|
||||
|
||||
storage->buffer_orphan_and_upload(data.polygon_buffer_size, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_vertices, GL_ARRAY_BUFFER, _buffer_upload_usage_flag);
|
||||
|
||||
glEnableVertexAttribArray(VS::ARRAY_VERTEX);
|
||||
glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, false, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buffer_ofs));
|
||||
buffer_ofs += sizeof(Vector2) * p_vertex_count;
|
||||
//color
|
||||
#ifdef DEBUG_ENABLED
|
||||
ERR_FAIL_COND(buffer_ofs > data.polygon_buffer_size);
|
||||
#endif
|
||||
buffer_ofs = buffer_ofs_after;
|
||||
|
||||
//color
|
||||
if (p_singlecolor) {
|
||||
glDisableVertexAttribArray(VS::ARRAY_COLOR);
|
||||
Color m = *p_colors;
|
||||
|
@ -368,44 +370,33 @@ void RasterizerCanvasBaseGLES3::_draw_polygon(const int *p_indices, int p_index_
|
|||
glDisableVertexAttribArray(VS::ARRAY_COLOR);
|
||||
glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1);
|
||||
} else {
|
||||
|
||||
glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Color) * p_vertex_count, p_colors);
|
||||
RAST_FAIL_COND(!storage->safe_buffer_sub_data(data.polygon_buffer_size, GL_ARRAY_BUFFER, buffer_ofs, sizeof(Color) * p_vertex_count, p_colors, buffer_ofs_after));
|
||||
glEnableVertexAttribArray(VS::ARRAY_COLOR);
|
||||
glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, false, sizeof(Color), CAST_INT_TO_UCHAR_PTR(buffer_ofs));
|
||||
buffer_ofs += sizeof(Color) * p_vertex_count;
|
||||
buffer_ofs = buffer_ofs_after;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
ERR_FAIL_COND(buffer_ofs > data.polygon_buffer_size);
|
||||
#endif
|
||||
|
||||
if (p_uvs) {
|
||||
|
||||
glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_uvs);
|
||||
RAST_FAIL_COND(!storage->safe_buffer_sub_data(data.polygon_buffer_size, GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_uvs, buffer_ofs_after));
|
||||
glEnableVertexAttribArray(VS::ARRAY_TEX_UV);
|
||||
glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, false, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buffer_ofs));
|
||||
buffer_ofs += sizeof(Vector2) * p_vertex_count;
|
||||
buffer_ofs = buffer_ofs_after;
|
||||
|
||||
} else {
|
||||
glDisableVertexAttribArray(VS::ARRAY_TEX_UV);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
ERR_FAIL_COND(buffer_ofs > data.polygon_buffer_size);
|
||||
#endif
|
||||
|
||||
if (p_bones && p_weights) {
|
||||
|
||||
glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(int) * 4 * p_vertex_count, p_bones);
|
||||
RAST_FAIL_COND(!storage->safe_buffer_sub_data(data.polygon_buffer_size, GL_ARRAY_BUFFER, buffer_ofs, sizeof(int) * 4 * p_vertex_count, p_bones, buffer_ofs_after));
|
||||
glEnableVertexAttribArray(VS::ARRAY_BONES);
|
||||
//glVertexAttribPointer(VS::ARRAY_BONES, 4, GL_UNSIGNED_INT, false, sizeof(int) * 4, ((uint8_t *)0) + buffer_ofs);
|
||||
glVertexAttribIPointer(VS::ARRAY_BONES, 4, GL_UNSIGNED_INT, sizeof(int) * 4, CAST_INT_TO_UCHAR_PTR(buffer_ofs));
|
||||
buffer_ofs += sizeof(int) * 4 * p_vertex_count;
|
||||
buffer_ofs = buffer_ofs_after;
|
||||
|
||||
glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(float) * 4 * p_vertex_count, p_weights);
|
||||
RAST_FAIL_COND(!storage->safe_buffer_sub_data(data.polygon_buffer_size, GL_ARRAY_BUFFER, buffer_ofs, sizeof(float) * 4 * p_vertex_count, p_weights, buffer_ofs_after));
|
||||
glEnableVertexAttribArray(VS::ARRAY_WEIGHTS);
|
||||
glVertexAttribPointer(VS::ARRAY_WEIGHTS, 4, GL_FLOAT, false, sizeof(float) * 4, CAST_INT_TO_UCHAR_PTR(buffer_ofs));
|
||||
buffer_ofs += sizeof(float) * 4 * p_vertex_count;
|
||||
buffer_ofs = buffer_ofs_after;
|
||||
|
||||
} else if (state.using_skeleton) {
|
||||
glVertexAttribI4ui(VS::ARRAY_BONES, 0, 0, 0, 0);
|
||||
|
@ -413,7 +404,7 @@ void RasterizerCanvasBaseGLES3::_draw_polygon(const int *p_indices, int p_index_
|
|||
}
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
ERR_FAIL_COND(buffer_ofs > data.polygon_buffer_size);
|
||||
ERR_FAIL_COND((sizeof(int) * p_index_count) > data.polygon_index_buffer_size);
|
||||
#endif
|
||||
|
||||
//bind the indices buffer.
|
||||
|
@ -442,11 +433,15 @@ void RasterizerCanvasBaseGLES3::_draw_generic(GLuint p_primitive, int p_vertex_c
|
|||
|
||||
//vertex
|
||||
uint32_t buffer_ofs = 0;
|
||||
uint32_t buffer_ofs_after = buffer_ofs + (sizeof(Vector2) * p_vertex_count);
|
||||
#ifdef DEBUG_ENABLED
|
||||
ERR_FAIL_COND(buffer_ofs_after > data.polygon_buffer_size);
|
||||
#endif
|
||||
storage->buffer_orphan_and_upload(data.polygon_buffer_size, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_vertices, GL_ARRAY_BUFFER, _buffer_upload_usage_flag);
|
||||
|
||||
glEnableVertexAttribArray(VS::ARRAY_VERTEX);
|
||||
glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, false, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buffer_ofs));
|
||||
buffer_ofs += sizeof(Vector2) * p_vertex_count;
|
||||
buffer_ofs = buffer_ofs_after;
|
||||
|
||||
//color
|
||||
if (p_singlecolor) {
|
||||
|
@ -457,19 +452,17 @@ void RasterizerCanvasBaseGLES3::_draw_generic(GLuint p_primitive, int p_vertex_c
|
|||
glDisableVertexAttribArray(VS::ARRAY_COLOR);
|
||||
glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1);
|
||||
} else {
|
||||
|
||||
glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Color) * p_vertex_count, p_colors);
|
||||
RAST_FAIL_COND(!storage->safe_buffer_sub_data(data.polygon_buffer_size, GL_ARRAY_BUFFER, buffer_ofs, sizeof(Color) * p_vertex_count, p_colors, buffer_ofs_after));
|
||||
glEnableVertexAttribArray(VS::ARRAY_COLOR);
|
||||
glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, false, sizeof(Color), CAST_INT_TO_UCHAR_PTR(buffer_ofs));
|
||||
buffer_ofs += sizeof(Color) * p_vertex_count;
|
||||
buffer_ofs = buffer_ofs_after;
|
||||
}
|
||||
|
||||
if (p_uvs) {
|
||||
|
||||
glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_uvs);
|
||||
RAST_FAIL_COND(!storage->safe_buffer_sub_data(data.polygon_buffer_size, GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_uvs, buffer_ofs_after));
|
||||
glEnableVertexAttribArray(VS::ARRAY_TEX_UV);
|
||||
glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, false, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buffer_ofs));
|
||||
buffer_ofs += sizeof(Vector2) * p_vertex_count;
|
||||
buffer_ofs = buffer_ofs_after;
|
||||
|
||||
} else {
|
||||
glDisableVertexAttribArray(VS::ARRAY_TEX_UV);
|
||||
|
@ -490,16 +483,17 @@ void RasterizerCanvasBaseGLES3::_draw_generic_indices(GLuint p_primitive, const
|
|||
|
||||
//vertex
|
||||
uint32_t buffer_ofs = 0;
|
||||
uint32_t buffer_ofs_after = buffer_ofs + (sizeof(Vector2) * p_vertex_count);
|
||||
#ifdef DEBUG_ENABLED
|
||||
ERR_FAIL_COND(buffer_ofs_after > data.polygon_buffer_size);
|
||||
#endif
|
||||
storage->buffer_orphan_and_upload(data.polygon_buffer_size, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_vertices, GL_ARRAY_BUFFER, _buffer_upload_usage_flag);
|
||||
|
||||
glEnableVertexAttribArray(VS::ARRAY_VERTEX);
|
||||
glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, false, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buffer_ofs));
|
||||
buffer_ofs += sizeof(Vector2) * p_vertex_count;
|
||||
//color
|
||||
#ifdef DEBUG_ENABLED
|
||||
ERR_FAIL_COND(buffer_ofs > data.polygon_buffer_size);
|
||||
#endif
|
||||
buffer_ofs = buffer_ofs_after;
|
||||
|
||||
//color
|
||||
if (p_singlecolor) {
|
||||
glDisableVertexAttribArray(VS::ARRAY_COLOR);
|
||||
Color m = *p_colors;
|
||||
|
@ -508,32 +502,22 @@ void RasterizerCanvasBaseGLES3::_draw_generic_indices(GLuint p_primitive, const
|
|||
glDisableVertexAttribArray(VS::ARRAY_COLOR);
|
||||
glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1);
|
||||
} else {
|
||||
|
||||
glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Color) * p_vertex_count, p_colors);
|
||||
RAST_FAIL_COND(!storage->safe_buffer_sub_data(data.polygon_buffer_size, GL_ARRAY_BUFFER, buffer_ofs, sizeof(Color) * p_vertex_count, p_colors, buffer_ofs_after));
|
||||
glEnableVertexAttribArray(VS::ARRAY_COLOR);
|
||||
glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, false, sizeof(Color), CAST_INT_TO_UCHAR_PTR(buffer_ofs));
|
||||
buffer_ofs += sizeof(Color) * p_vertex_count;
|
||||
buffer_ofs = buffer_ofs_after;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
ERR_FAIL_COND(buffer_ofs > data.polygon_buffer_size);
|
||||
#endif
|
||||
|
||||
if (p_uvs) {
|
||||
|
||||
glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_uvs);
|
||||
RAST_FAIL_COND(!storage->safe_buffer_sub_data(data.polygon_buffer_size, GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_uvs, buffer_ofs_after));
|
||||
glEnableVertexAttribArray(VS::ARRAY_TEX_UV);
|
||||
glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, false, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buffer_ofs));
|
||||
buffer_ofs += sizeof(Vector2) * p_vertex_count;
|
||||
buffer_ofs = buffer_ofs_after;
|
||||
|
||||
} else {
|
||||
glDisableVertexAttribArray(VS::ARRAY_TEX_UV);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
ERR_FAIL_COND(buffer_ofs > data.polygon_buffer_size);
|
||||
#endif
|
||||
|
||||
#ifdef RASTERIZER_EXTRA_CHECKS
|
||||
// very slow, do not enable in normal use
|
||||
for (int n = 0; n < p_index_count; n++) {
|
||||
|
@ -541,6 +525,10 @@ void RasterizerCanvasBaseGLES3::_draw_generic_indices(GLuint p_primitive, const
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
ERR_FAIL_COND((sizeof(int) * p_index_count) > data.polygon_index_buffer_size);
|
||||
#endif
|
||||
|
||||
//bind the indices buffer.
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer);
|
||||
storage->buffer_orphan_and_upload(data.polygon_index_buffer_size, 0, sizeof(int) * p_index_count, p_indices, GL_ELEMENT_ARRAY_BUFFER, _buffer_upload_usage_flag);
|
||||
|
@ -584,6 +572,7 @@ void RasterizerCanvasBaseGLES3::_draw_gui_primitive(int p_points, const Vector2
|
|||
stride += 1;
|
||||
}
|
||||
|
||||
RAST_DEV_DEBUG_ASSERT(p_points <= 4);
|
||||
float b[(2 + 2 + 4 + 1) * 4];
|
||||
|
||||
for (int i = 0; i < p_points; i++) {
|
||||
|
@ -1218,8 +1207,8 @@ void RasterizerCanvasBaseGLES3::initialize() {
|
|||
|
||||
uint32_t poly_size = GLOBAL_DEF_RST("rendering/limits/buffers/canvas_polygon_buffer_size_kb", 128);
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/buffers/canvas_polygon_buffer_size_kb", PropertyInfo(Variant::INT, "rendering/limits/buffers/canvas_polygon_buffer_size_kb", PROPERTY_HINT_RANGE, "0,256,1,or_greater"));
|
||||
poly_size = MAX(poly_size, 2); // minimum 2k, may still see anomalies in editor
|
||||
poly_size *= 1024; //kb
|
||||
poly_size = MAX(poly_size, (2 + 2 + 4 + 1) * 4 * sizeof(float));
|
||||
glGenBuffers(1, &data.polygon_buffer);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, poly_size, NULL, GL_DYNAMIC_DRAW); //allocate max size
|
||||
|
@ -1278,6 +1267,7 @@ void RasterizerCanvasBaseGLES3::initialize() {
|
|||
|
||||
uint32_t index_size = GLOBAL_DEF_RST("rendering/limits/buffers/canvas_polygon_index_buffer_size_kb", 128);
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/buffers/canvas_polygon_index_buffer_size_kb", PropertyInfo(Variant::INT, "rendering/limits/buffers/canvas_polygon_index_buffer_size_kb", PROPERTY_HINT_RANGE, "0,256,1,or_greater"));
|
||||
index_size = MAX(index_size, 2);
|
||||
index_size *= 1024; //kb
|
||||
glGenBuffers(1, &data.polygon_index_buffer);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer);
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
/*************************************************************************/
|
||||
|
||||
#include "rasterizer_canvas_gles3.h"
|
||||
|
||||
#include "drivers/gles_common/rasterizer_asserts.h"
|
||||
#include "servers/visual/visual_server_raster.h"
|
||||
|
||||
static const GLenum gl_primitive[] = {
|
||||
|
@ -595,6 +597,11 @@ void RasterizerCanvasGLES3::render_batches(Item::Command *const *p_commands, Ite
|
|||
|
||||
if (pline->triangles.size()) {
|
||||
|
||||
#ifdef RASTERIZER_EXTRA_CHECKS
|
||||
if (pline->triangle_colors.ptr() && (pline->triangle_colors.size() != 1)) {
|
||||
RAST_DEV_DEBUG_ASSERT(pline->triangle_colors.size() == pline->triangles.size());
|
||||
}
|
||||
#endif
|
||||
_draw_generic(GL_TRIANGLE_STRIP, pline->triangles.size(), pline->triangles.ptr(), NULL, pline->triangle_colors.ptr(), pline->triangle_colors.size() == 1);
|
||||
#ifdef GLES_OVER_GL
|
||||
glEnable(GL_LINE_SMOOTH);
|
||||
|
@ -774,16 +781,30 @@ void RasterizerCanvasGLES3::render_batches(Item::Command *const *p_commands, Ite
|
|||
Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height);
|
||||
state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size);
|
||||
}
|
||||
|
||||
// we need a temporary because this must be nulled out
|
||||
// if only a single color specified
|
||||
const Color *colors = primitive->colors.ptr();
|
||||
if (primitive->colors.size() == 1 && primitive->points.size() > 1) {
|
||||
|
||||
Color col = primitive->colors[0];
|
||||
glVertexAttrib4f(VS::ARRAY_COLOR, col.r, col.g, col.b, col.a);
|
||||
colors = nullptr;
|
||||
|
||||
} else if (primitive->colors.empty()) {
|
||||
glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1);
|
||||
}
|
||||
#ifdef RASTERIZER_EXTRA_CHECKS
|
||||
else {
|
||||
RAST_DEV_DEBUG_ASSERT(primitive->colors.size() == primitive->points.size());
|
||||
}
|
||||
|
||||
_draw_gui_primitive(primitive->points.size(), primitive->points.ptr(), primitive->colors.ptr(), primitive->uvs.ptr());
|
||||
if (primitive->uvs.ptr()) {
|
||||
RAST_DEV_DEBUG_ASSERT(primitive->uvs.size() == primitive->points.size());
|
||||
}
|
||||
#endif
|
||||
|
||||
_draw_gui_primitive(primitive->points.size(), primitive->points.ptr(), colors, primitive->uvs.ptr());
|
||||
|
||||
} break;
|
||||
case Item::Command::TYPE_POLYGON: {
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#define RASTERIZERSTORAGEGLES3_H
|
||||
|
||||
#include "core/self_list.h"
|
||||
#include "drivers/gles_common/rasterizer_asserts.h"
|
||||
#include "servers/visual/rasterizer.h"
|
||||
#include "servers/visual/shader_language.h"
|
||||
#include "shader_compiler_gles3.h"
|
||||
|
@ -1509,19 +1510,46 @@ public:
|
|||
virtual String get_video_adapter_name() const;
|
||||
virtual String get_video_adapter_vendor() const;
|
||||
|
||||
void buffer_orphan_and_upload(unsigned int p_buffer_size, unsigned int p_offset, unsigned int p_data_size, const void *p_data, GLenum p_target = GL_ARRAY_BUFFER, GLenum p_usage = GL_DYNAMIC_DRAW, bool p_optional_orphan = false);
|
||||
void buffer_orphan_and_upload(unsigned int p_buffer_size, unsigned int p_offset, unsigned int p_data_size, const void *p_data, GLenum p_target = GL_ARRAY_BUFFER, GLenum p_usage = GL_DYNAMIC_DRAW, bool p_optional_orphan = false) const;
|
||||
bool safe_buffer_sub_data(unsigned int p_total_buffer_size, GLenum p_target, unsigned int p_offset, unsigned int p_data_size, const void *p_data, unsigned int &r_offset_after) const;
|
||||
|
||||
RasterizerStorageGLES3();
|
||||
};
|
||||
|
||||
inline bool RasterizerStorageGLES3::safe_buffer_sub_data(unsigned int p_total_buffer_size, GLenum p_target, unsigned int p_offset, unsigned int p_data_size, const void *p_data, unsigned int &r_offset_after) const {
|
||||
r_offset_after = p_offset + p_data_size;
|
||||
#ifdef DEBUG_ENABLED
|
||||
// we are trying to write across the edge of the buffer
|
||||
if (r_offset_after > p_total_buffer_size)
|
||||
return false;
|
||||
#endif
|
||||
glBufferSubData(p_target, p_offset, p_data_size, p_data);
|
||||
return true;
|
||||
}
|
||||
|
||||
// standardize the orphan / upload in one place so it can be changed per platform as necessary, and avoid future
|
||||
// bugs causing pipeline stalls
|
||||
inline void RasterizerStorageGLES3::buffer_orphan_and_upload(unsigned int p_buffer_size, unsigned int p_offset, unsigned int p_data_size, const void *p_data, GLenum p_target, GLenum p_usage, bool p_optional_orphan) {
|
||||
inline void RasterizerStorageGLES3::buffer_orphan_and_upload(unsigned int p_buffer_size, unsigned int p_offset, unsigned int p_data_size, const void *p_data, GLenum p_target, GLenum p_usage, bool p_optional_orphan) const {
|
||||
// Orphan the buffer to avoid CPU/GPU sync points caused by glBufferSubData
|
||||
// Was previously #ifndef GLES_OVER_GL however this causes stalls on desktop mac also (and possibly other)
|
||||
if (!p_optional_orphan || (config.should_orphan)) {
|
||||
glBufferData(p_target, p_buffer_size, NULL, p_usage);
|
||||
#ifdef RASTERIZER_EXTRA_CHECKS
|
||||
// fill with garbage off the end of the array
|
||||
if (p_buffer_size) {
|
||||
unsigned int start = p_offset + p_data_size;
|
||||
unsigned int end = start + 1024;
|
||||
if (end < p_buffer_size) {
|
||||
uint8_t *garbage = (uint8_t *)alloca(1024);
|
||||
for (int n = 0; n < 1024; n++) {
|
||||
garbage[n] = Math::random(0, 255);
|
||||
}
|
||||
glBufferSubData(p_target, start, 1024, garbage);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
RAST_DEV_DEBUG_ASSERT((p_offset + p_data_size) <= p_buffer_size);
|
||||
glBufferSubData(p_target, p_offset, p_data_size, p_data);
|
||||
}
|
||||
|
||||
|
|
|
@ -55,4 +55,13 @@
|
|||
#define RAST_DEBUG_ASSERT(a)
|
||||
#endif
|
||||
|
||||
// Thin wrapper around ERR_FAIL_COND to allow us to make it debug only
|
||||
#ifdef DEBUG_ENABLED
|
||||
#define RAST_FAIL_COND(m_cond) ERR_FAIL_COND(m_cond)
|
||||
#else
|
||||
#define RAST_FAIL_COND(m_cond) \
|
||||
if (m_cond) { \
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // RASTERIZER_ASSERTS_H
|
||||
|
|
Loading…
Reference in New Issue