From e88b4f330eae73ba14bf59492143f8f1093f719a Mon Sep 17 00:00:00 2001 From: lawnjelly Date: Thu, 12 Nov 2020 19:16:33 +0000 Subject: [PATCH] Poly colors fixes This adds support for custom shaders for polys, and properly handles modulate in the case of large FVF and modulate FVF. It also fixes poly vertex colors not being sent to OpenGL. --- drivers/gles2/rasterizer_canvas_gles2.cpp | 88 +++++---------- drivers/gles2/rasterizer_canvas_gles2.h | 3 +- drivers/gles2/shaders/canvas.glsl | 8 +- drivers/gles3/rasterizer_canvas_gles3.cpp | 100 ++++++++++-------- drivers/gles3/rasterizer_canvas_gles3.h | 4 +- drivers/gles3/shaders/canvas.glsl | 11 +- .../gles_common/rasterizer_canvas_batcher.h | 75 ++++++++++++- 7 files changed, 164 insertions(+), 125 deletions(-) diff --git a/drivers/gles2/rasterizer_canvas_gles2.cpp b/drivers/gles2/rasterizer_canvas_gles2.cpp index f29f1caae4..f7b1546d5e 100644 --- a/drivers/gles2/rasterizer_canvas_gles2.cpp +++ b/drivers/gles2/rasterizer_canvas_gles2.cpp @@ -135,60 +135,13 @@ void RasterizerCanvasGLES2::_batch_render_lines(const Batch &p_batch, Rasterizer #endif } -void RasterizerCanvasGLES2::_batch_render_polys(const Batch &p_batch, RasterizerStorageGLES2::Material *p_material) { - - _set_texture_rect_mode(false); - - if (state.canvas_shader.bind()) { - _set_uniforms(); - state.canvas_shader.use_material((void *)p_material); - } - - // batch tex - const BatchTex &tex = bdata.batch_textures[p_batch.batch_texture_id]; - _bind_canvas_texture(tex.RID_texture, tex.RID_normal); - - // state.canvas_shader.set_uniform(CanvasShaderGLES2::MODELVIEW_MATRIX, Transform()); - - int sizeof_vert = sizeof(BatchVertexColored); - - // bind the index and vertex buffer - glBindBuffer(GL_ARRAY_BUFFER, bdata.gl_vertex_buffer); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bdata.gl_index_buffer); - - uint64_t pointer = 0; - glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof_vert, (const void *)pointer); - - glEnableVertexAttribArray(VS::ARRAY_TEX_UV); - glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof_vert, CAST_INT_TO_UCHAR_PTR(pointer + (2 * 4))); - - glEnableVertexAttribArray(VS::ARRAY_COLOR); - glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof_vert, CAST_INT_TO_UCHAR_PTR(pointer + (4 * 4))); - - int64_t offset = p_batch.first_vert; // 6 inds per quad at 2 bytes each - - int num_elements = p_batch.num_commands; - glDrawArrays(GL_TRIANGLES, offset, num_elements); - - storage->info.render._2d_draw_call_count++; - - // could these have ifs? - glDisableVertexAttribArray(VS::ARRAY_TEX_UV); - glDisableVertexAttribArray(VS::ARRAY_COLOR); - - // may not be necessary .. state change optimization still TODO - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); -} - -void RasterizerCanvasGLES2::_batch_render_rects(const Batch &p_batch, RasterizerStorageGLES2::Material *p_material) { - +void RasterizerCanvasGLES2::_batch_render_generic(const Batch &p_batch, RasterizerStorageGLES2::Material *p_material) { ERR_FAIL_COND(p_batch.num_commands <= 0); - const bool &colored_verts = bdata.use_colored_vertices; const bool &use_light_angles = bdata.use_light_angles; const bool &use_modulate = bdata.use_modulate; const bool &use_large_verts = bdata.use_large_verts; + const bool &colored_verts = bdata.use_colored_vertices | use_light_angles | use_modulate | use_large_verts; int sizeof_vert; @@ -196,9 +149,10 @@ void RasterizerCanvasGLES2::_batch_render_rects(const Batch &p_batch, Rasterizer default: sizeof_vert = 0; // prevent compiler warning - this should never happen break; - case RasterizerStorageCommon::FVF_UNBATCHED: // should not happen + case RasterizerStorageCommon::FVF_UNBATCHED: { + sizeof_vert = 0; // prevent compiler warning - this should never happen return; - break; + } break; case RasterizerStorageCommon::FVF_REGULAR: // no change sizeof_vert = sizeof(BatchVertex); break; @@ -216,13 +170,11 @@ void RasterizerCanvasGLES2::_batch_render_rects(const Batch &p_batch, Rasterizer break; } - // batch tex - const BatchTex &tex = bdata.batch_textures[p_batch.batch_texture_id]; - // make sure to set all conditionals BEFORE binding the shader - //state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false); _set_texture_rect_mode(false, use_light_angles, use_modulate, use_large_verts); + // batch tex + const BatchTex &tex = bdata.batch_textures[p_batch.batch_texture_id]; //VSG::rasterizer->gl_check_for_error(); // force repeat is set if non power of 2 texture, and repeat is needed if hardware doesn't support npot @@ -235,9 +187,6 @@ void RasterizerCanvasGLES2::_batch_render_rects(const Batch &p_batch, Rasterizer state.canvas_shader.use_material((void *)p_material); } - // batch tex - //const BatchTex &tex = bdata.batch_textures[p_batch.batch_texture_id]; - _bind_canvas_texture(tex.RID_texture, tex.RID_normal); // bind the index and vertex buffer @@ -297,10 +246,23 @@ void RasterizerCanvasGLES2::_batch_render_rects(const Batch &p_batch, Rasterizer tex.tex_pixel_size.to(tps); state.canvas_shader.set_uniform(CanvasShaderGLES2::COLOR_TEXPIXEL_SIZE, tps); - int64_t offset = p_batch.first_vert * 3; + switch (p_batch.type) { + default: { + // prevent compiler warning + } break; + case RasterizerStorageCommon::BT_RECT: { + int64_t offset = p_batch.first_vert * 3; - int num_elements = p_batch.num_commands * 6; - glDrawElements(GL_TRIANGLES, num_elements, GL_UNSIGNED_SHORT, (void *)offset); + int num_elements = p_batch.num_commands * 6; + glDrawElements(GL_TRIANGLES, num_elements, GL_UNSIGNED_SHORT, (void *)offset); + } break; + case RasterizerStorageCommon::BT_POLY: { + int64_t offset = p_batch.first_vert; + + int num_elements = p_batch.num_commands; + glDrawArrays(GL_TRIANGLES, offset, num_elements); + } break; + } storage->info.render._2d_draw_call_count++; @@ -341,10 +303,10 @@ void RasterizerCanvasGLES2::render_batches(Item::Command *const *p_commands, Ite switch (batch.type) { case RasterizerStorageCommon::BT_RECT: { - _batch_render_rects(batch, p_material); + _batch_render_generic(batch, p_material); } break; case RasterizerStorageCommon::BT_POLY: { - _batch_render_polys(batch, p_material); + _batch_render_generic(batch, p_material); } break; case RasterizerStorageCommon::BT_LINE: { _batch_render_lines(batch, p_material, false); diff --git a/drivers/gles2/rasterizer_canvas_gles2.h b/drivers/gles2/rasterizer_canvas_gles2.h index b5518d336f..50853df46a 100644 --- a/drivers/gles2/rasterizer_canvas_gles2.h +++ b/drivers/gles2/rasterizer_canvas_gles2.h @@ -59,8 +59,7 @@ private: // low level batch funcs void _batch_upload_buffers(); - void _batch_render_rects(const Batch &p_batch, RasterizerStorageGLES2::Material *p_material); - void _batch_render_polys(const Batch &p_batch, RasterizerStorageGLES2::Material *p_material); + void _batch_render_generic(const Batch &p_batch, RasterizerStorageGLES2::Material *p_material); void _batch_render_lines(const Batch &p_batch, RasterizerStorageGLES2::Material *p_material, bool p_anti_alias); // funcs used from rasterizer_canvas_batcher template diff --git a/drivers/gles2/shaders/canvas.glsl b/drivers/gles2/shaders/canvas.glsl index ecb53ee40b..444839ff9b 100644 --- a/drivers/gles2/shaders/canvas.glsl +++ b/drivers/gles2/shaders/canvas.glsl @@ -479,13 +479,13 @@ FRAGMENT_SHADER_CODE normal = mix(vec3(0.0, 0.0, 1.0), normal_map * vec3(2.0, -2.0, 1.0) - vec3(1.0, -1.0, 0.0), normal_depth); #endif } + +#ifdef USE_ATTRIB_MODULATE + color *= modulate_interp; +#else #if !defined(MODULATE_USED) color *= final_modulate; #endif - -#ifdef USE_ATTRIB_MODULATE - // todo .. this won't be used at the same time as MODULATE_USED - color *= modulate_interp; #endif #ifdef USE_LIGHTING diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index 9bb66e26bf..66ba398291 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -511,10 +511,10 @@ void RasterizerCanvasGLES3::render_batches(Item::Command *const *p_commands, Ite switch (batch.type) { case RasterizerStorageCommon::BT_RECT: { - _batch_render_rects(batch, p_material); + _batch_render_generic(batch, p_material); } break; case RasterizerStorageCommon::BT_POLY: { - _batch_render_polys(batch, p_material); + _batch_render_generic(batch, p_material); } break; case RasterizerStorageCommon::BT_LINE: { _batch_render_lines(batch, p_material, false); @@ -2036,43 +2036,8 @@ void RasterizerCanvasGLES3::_batch_render_lines(const Batch &p_batch, Rasterizer #endif } -void RasterizerCanvasGLES3::_batch_render_polys(const Batch &p_batch, RasterizerStorageGLES3::Material *p_material) { - ERR_FAIL_COND(p_batch.num_commands <= 0); - - _set_texture_rect_mode(false); - state.canvas_shader.set_uniform(CanvasShaderGLES3::CLIP_RECT_UV, false); - - glBindVertexArray(batch_gl_data.batch_vertex_array[1]); - - // batch tex - const BatchTex &tex = bdata.batch_textures[p_batch.batch_texture_id]; - - _bind_canvas_texture(tex.RID_texture, tex.RID_normal); - - // may not need this disable - // glDisableVertexAttribArray(VS::ARRAY_COLOR); - // glVertexAttrib4fv(VS::ARRAY_COLOR, p_batch.color.get_data()); - - // we need to convert explicitly from pod Vec2 to Vector2 ... - // could use a cast but this might be unsafe in future - Vector2 tps; - tex.tex_pixel_size.to(tps); - state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, tps); - - int64_t offset = p_batch.first_vert; - - int num_elements = p_batch.num_commands; - glDrawArrays(GL_TRIANGLES, offset, num_elements); - - storage->info.render._2d_draw_call_count++; - - glBindVertexArray(0); -} - -void RasterizerCanvasGLES3::_batch_render_rects(const Batch &p_batch, RasterizerStorageGLES3::Material *p_material) { - ERR_FAIL_COND(p_batch.num_commands <= 0); - - const bool &colored_verts = bdata.use_colored_vertices; +void RasterizerCanvasGLES3::_batch_render_prepare() { + //const bool &colored_verts = bdata.use_colored_vertices; const bool &use_light_angles = bdata.use_light_angles; const bool &use_modulate = bdata.use_modulate; const bool &use_large_verts = bdata.use_large_verts; @@ -2102,11 +2067,41 @@ void RasterizerCanvasGLES3::_batch_render_rects(const Batch &p_batch, Rasterizer glBindVertexArray(batch_gl_data.batch_vertex_array[4]); break; } +} - // if (state.canvas_shader.bind()) { - // _set_uniforms(); - // state.canvas_shader.use_material((void *)p_material); - // } +void RasterizerCanvasGLES3::_batch_render_generic(const Batch &p_batch, RasterizerStorageGLES3::Material *p_material) { + ERR_FAIL_COND(p_batch.num_commands <= 0); + + const bool &use_light_angles = bdata.use_light_angles; + const bool &use_modulate = bdata.use_modulate; + const bool &use_large_verts = bdata.use_large_verts; + const bool &colored_verts = bdata.use_colored_vertices | use_light_angles | use_modulate | use_large_verts; + + _set_texture_rect_mode(false, false, use_light_angles, use_modulate, use_large_verts); + + // state.canvas_shader.set_uniform(CanvasShaderGLES3::CLIP_RECT_UV, p_rect->flags & CANVAS_RECT_CLIP_UV); + state.canvas_shader.set_uniform(CanvasShaderGLES3::CLIP_RECT_UV, false); + + switch (bdata.fvf) { + case RasterizerStorageCommon::FVF_UNBATCHED: // should not happen + return; + break; + case RasterizerStorageCommon::FVF_REGULAR: // no change + glBindVertexArray(batch_gl_data.batch_vertex_array[0]); + break; + case RasterizerStorageCommon::FVF_COLOR: + glBindVertexArray(batch_gl_data.batch_vertex_array[1]); + break; + case RasterizerStorageCommon::FVF_LIGHT_ANGLE: + glBindVertexArray(batch_gl_data.batch_vertex_array[2]); + break; + case RasterizerStorageCommon::FVF_MODULATED: + glBindVertexArray(batch_gl_data.batch_vertex_array[3]); + break; + case RasterizerStorageCommon::FVF_LARGE: + glBindVertexArray(batch_gl_data.batch_vertex_array[4]); + break; + } // batch tex const BatchTex &tex = bdata.batch_textures[p_batch.batch_texture_id]; @@ -2143,10 +2138,23 @@ void RasterizerCanvasGLES3::_batch_render_rects(const Batch &p_batch, Rasterizer tex.tex_pixel_size.to(tps); state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, tps); - int64_t offset = p_batch.first_vert * 3; // 6 inds per quad at 2 bytes each + switch (p_batch.type) { + default: { + // prevent compiler warning + } break; + case RasterizerStorageCommon::BT_RECT: { + int64_t offset = p_batch.first_vert * 3; // 6 inds per quad at 2 bytes each - int num_elements = p_batch.num_commands * 6; - glDrawElements(GL_TRIANGLES, num_elements, GL_UNSIGNED_SHORT, (void *)offset); + int num_elements = p_batch.num_commands * 6; + glDrawElements(GL_TRIANGLES, num_elements, GL_UNSIGNED_SHORT, (void *)offset); + } break; + case RasterizerStorageCommon::BT_POLY: { + int64_t offset = p_batch.first_vert; + + int num_elements = p_batch.num_commands; + glDrawArrays(GL_TRIANGLES, offset, num_elements); + } break; + } storage->info.render._2d_draw_call_count++; diff --git a/drivers/gles3/rasterizer_canvas_gles3.h b/drivers/gles3/rasterizer_canvas_gles3.h index cec859fee7..c4dd74b86c 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.h +++ b/drivers/gles3/rasterizer_canvas_gles3.h @@ -62,8 +62,8 @@ private: // low level batch funcs void _batch_upload_buffers(); - void _batch_render_rects(const Batch &p_batch, RasterizerStorageGLES3::Material *p_material); - void _batch_render_polys(const Batch &p_batch, RasterizerStorageGLES3::Material *p_material); + void _batch_render_prepare(); + void _batch_render_generic(const Batch &p_batch, RasterizerStorageGLES3::Material *p_material); void _batch_render_lines(const Batch &p_batch, RasterizerStorageGLES3::Material *p_material, bool p_anti_alias); // funcs used from rasterizer_canvas_batcher template diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl index 116a4da8aa..9a1122c920 100644 --- a/drivers/gles3/shaders/canvas.glsl +++ b/drivers/gles3/shaders/canvas.glsl @@ -66,7 +66,7 @@ out mediump vec4 color_interp; #ifdef USE_ATTRIB_MODULATE // modulate doesn't need interpolating but we need to send it to the fragment shader -out mediump vec4 modulate_interp; +flat out mediump vec4 modulate_interp; #endif #ifdef MODULATE_USED @@ -332,7 +332,7 @@ in highp vec2 uv_interp; in mediump vec4 color_interp; #ifdef USE_ATTRIB_MODULATE -in mediump vec4 modulate_interp; +flat in mediump vec4 modulate_interp; #endif #if defined(SCREEN_TEXTURE_USED) @@ -582,13 +582,12 @@ FRAGMENT_SHADER_CODE color = vec4(vec3(enc32), 1.0); #endif +#ifdef USE_ATTRIB_MODULATE + color *= modulate_interp; +#else #if !defined(MODULATE_USED) color *= final_modulate; #endif - -#ifdef USE_ATTRIB_MODULATE - // todo .. this won't be used at the same time as MODULATE_USED - color *= modulate_interp; #endif #ifdef USE_LIGHTING diff --git a/drivers/gles_common/rasterizer_canvas_batcher.h b/drivers/gles_common/rasterizer_canvas_batcher.h index 05b950e789..2f8657274a 100644 --- a/drivers/gles_common/rasterizer_canvas_batcher.h +++ b/drivers/gles_common/rasterizer_canvas_batcher.h @@ -1492,9 +1492,42 @@ bool C_PREAMBLE::_prefill_polygon(RasterizerCanvas::Item::CommandPolygon *p_poly CRASH_COND(!vertex_colors); #endif + // are we using large FVF? + //////////////////////////////////// + const bool use_large_verts = bdata.use_large_verts; + const bool use_modulate = bdata.use_modulate; + + BatchColor *vertex_modulates = nullptr; + if (use_modulate) { + vertex_modulates = bdata.vertex_modulates.request(num_inds); +#if defined(TOOLS_ENABLED) && defined(DEBUG_ENABLED) + CRASH_COND(!vertex_modulates); +#endif + // precalc the vertex modulate (will be shared by all verts) + // we store the modulate as an attribute in the fvf rather than a uniform + vertex_modulates[0].set(r_fill_state.final_modulate); + } + + BatchTransform *pBT = nullptr; + if (use_large_verts) { + pBT = bdata.vertex_transforms.request(num_inds); +#if defined(TOOLS_ENABLED) && defined(DEBUG_ENABLED) + CRASH_COND(!pBT); +#endif + // precalc the batch transform (will be shared by all verts) + // we store the transform as an attribute in the fvf rather than a uniform + const Transform2D &tr = r_fill_state.transform_combined; + + pBT[0].translate.set(tr.elements[2]); + // could do swizzling in shader? + pBT[0].basis[0].set(tr.elements[0][0], tr.elements[1][0]); + pBT[0].basis[1].set(tr.elements[0][1], tr.elements[1][1]); + } + //////////////////////////////////// + // the modulate is always baked Color modulate; - if (multiply_final_modulate) + if (!use_large_verts && !use_modulate && multiply_final_modulate) modulate = r_fill_state.final_modulate; else modulate = Color(1, 1, 1, 1); @@ -1508,6 +1541,11 @@ bool C_PREAMBLE::_prefill_polygon(RasterizerCanvas::Item::CommandPolygon *p_poly } // N.B. polygons don't have color thus don't need a batch change with color + // This code is left as reference in case of problems. + // if (!r_fill_state.curr_batch->color.equals(modulate)) { + // change_batch = true; + // bdata.total_color_changes++; + // } if (change_batch) { // put the tex pixel size in a local (less verbose and can be a register) @@ -1586,8 +1624,32 @@ bool C_PREAMBLE::_prefill_polygon(RasterizerCanvas::Item::CommandPolygon *p_poly } vertex_colors[n] = precalced_colors[ind]; + + if (use_modulate) { + vertex_modulates[n] = vertex_modulates[0]; + } + + if (use_large_verts) { + // reuse precalced transform (same for each vertex within polygon) + pBT[n] = pBT[0]; + } } } // if not software skinning + else { + // software skinning extra passes + if (use_modulate) { + for (int n = 0; n < num_inds; n++) { + vertex_modulates[n] = vertex_modulates[0]; + } + } + // not sure if this will produce garbage if software skinning is changing vertex pos + // in the shader, but is included for completeness + if (use_large_verts) { + for (int n = 0; n < num_inds; n++) { + pBT[n] = pBT[0]; + } + } + } // increment total vert count bdata.total_verts += num_inds; @@ -2704,6 +2766,8 @@ T_PREAMBLE template void C_PREAMBLE::_translate_batches_to_larger_FVF() { + bool include_poly_color = INCLUDE_LIGHT_ANGLES | INCLUDE_MODULATE | INCLUDE_LARGE; + // zeros the size and sets up how big each unit is bdata.unit_vertices.prepare(sizeof(BATCH_VERTEX_TYPE)); bdata.batches_temp.reset(); @@ -2721,6 +2785,7 @@ void C_PREAMBLE::_translate_batches_to_larger_FVF() { Batch *dest_batch = nullptr; + const BatchColor *source_vertex_colors = &bdata.vertex_colors[0]; const float *source_light_angles = &bdata.light_angles[0]; const BatchColor *source_vertex_modulates = &bdata.vertex_modulates[0]; const BatchTransform *source_vertex_transforms = &bdata.vertex_transforms[0]; @@ -2817,7 +2882,13 @@ void C_PREAMBLE::_translate_batches_to_larger_FVF() { #endif cv->pos = bv.pos; cv->uv = bv.uv; - cv->col = source_batch.color; + + // polys are special, they can have per vertex colors + if (!include_poly_color) { + cv->col = source_batch.color; + } else { + cv->col = *source_vertex_colors++; + } if (INCLUDE_LIGHT_ANGLES) { // this is required to allow compilation with non light angle vertex.