diff options
Diffstat (limited to 'intern/opensubdiv/opensubdiv_gpu_capi.cc')
-rw-r--r-- | intern/opensubdiv/opensubdiv_gpu_capi.cc | 414 |
1 files changed, 269 insertions, 145 deletions
diff --git a/intern/opensubdiv/opensubdiv_gpu_capi.cc b/intern/opensubdiv/opensubdiv_gpu_capi.cc index 698fdfee00f..0cf6fcfef43 100644 --- a/intern/opensubdiv/opensubdiv_gpu_capi.cc +++ b/intern/opensubdiv/opensubdiv_gpu_capi.cc @@ -42,11 +42,29 @@ #include <opensubdiv/osd/cpuGLVertexBuffer.h> #include <opensubdiv/osd/cpuEvaluator.h> +#include "MEM_guardedalloc.h" + +#include "opensubdiv_capi.h" +#include "opensubdiv_topology_refiner.h" + using OpenSubdiv::Osd::GLMeshInterface; extern "C" char datatoc_gpu_shader_opensubd_display_glsl[]; +/* TODO(sergey): This is bit of bad level calls :S */ +extern "C" { +void copy_m3_m3(float m1[3][3], float m2[3][3]); +void copy_m3_m4(float m1[3][3], float m2[4][4]); +void adjoint_m3_m3(float m1[3][3], float m[3][3]); +float determinant_m3_array(float m[3][3]); +bool invert_m3_m3(float m1[3][3], float m2[3][3]); +bool invert_m3(float m[3][3]); +void transpose_m3(float mat[3][3]); +} + #define MAX_LIGHTS 8 +#define SUPPORT_COLOR_MATERIAL + typedef struct Light { float position[4]; float ambient[4]; @@ -60,6 +78,7 @@ typedef struct Light { float spot_cutoff; float spot_exponent; float spot_cos_cutoff; + float pad, pad2; #endif } Light; @@ -75,114 +94,116 @@ typedef struct Transform { } Transform; static bool g_use_osd_glsl = false; -static int g_active_uv_index = -1; +static int g_active_uv_index = 0; static GLuint g_flat_fill_solid_program = 0; static GLuint g_flat_fill_texture2d_program = 0; static GLuint g_smooth_fill_solid_program = 0; static GLuint g_smooth_fill_texture2d_program = 0; + +static GLuint g_flat_fill_solid_shadeless_program = 0; +static GLuint g_flat_fill_texture2d_shadeless_program = 0; +static GLuint g_smooth_fill_solid_shadeless_program = 0; +static GLuint g_smooth_fill_texture2d_shadeless_program = 0; + static GLuint g_wireframe_program = 0; static GLuint g_lighting_ub = 0; static Lighting g_lighting_data; static Transform g_transform; -/* TODO(sergey): This is actually duplicated code from BLI. */ -namespace { -void copy_m3_m3(float m1[3][3], float m2[3][3]) -{ - /* destination comes first: */ - memcpy(&m1[0], &m2[0], 9 * sizeof(float)); -} - -void copy_m3_m4(float m1[3][3], float m2[4][4]) -{ - m1[0][0] = m2[0][0]; - m1[0][1] = m2[0][1]; - m1[0][2] = m2[0][2]; - - m1[1][0] = m2[1][0]; - m1[1][1] = m2[1][1]; - m1[1][2] = m2[1][2]; - - m1[2][0] = m2[2][0]; - m1[2][1] = m2[2][1]; - m1[2][2] = m2[2][2]; -} - -void adjoint_m3_m3(float m1[3][3], float m[3][3]) -{ - m1[0][0] = m[1][1] * m[2][2] - m[1][2] * m[2][1]; - m1[0][1] = -m[0][1] * m[2][2] + m[0][2] * m[2][1]; - m1[0][2] = m[0][1] * m[1][2] - m[0][2] * m[1][1]; - - m1[1][0] = -m[1][0] * m[2][2] + m[1][2] * m[2][0]; - m1[1][1] = m[0][0] * m[2][2] - m[0][2] * m[2][0]; - m1[1][2] = -m[0][0] * m[1][2] + m[0][2] * m[1][0]; - - m1[2][0] = m[1][0] * m[2][1] - m[1][1] * m[2][0]; - m1[2][1] = -m[0][0] * m[2][1] + m[0][1] * m[2][0]; - m1[2][2] = m[0][0] * m[1][1] - m[0][1] * m[1][0]; -} - -float determinant_m3_array(float m[3][3]) +struct OpenSubdiv_GLMeshFVarData { - return (m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1]) - - m[1][0] * (m[0][1] * m[2][2] - m[0][2] * m[2][1]) + - m[2][0] * (m[0][1] * m[1][2] - m[0][2] * m[1][1])); -} - -bool invert_m3_m3(float m1[3][3], float m2[3][3]) -{ - float det; - int a, b; - bool success; - - /* calc adjoint */ - adjoint_m3_m3(m1, m2); + OpenSubdiv_GLMeshFVarData() : + texture_buffer(0) { + } - /* then determinant old matrix! */ - det = determinant_m3_array(m2); + ~OpenSubdiv_GLMeshFVarData() + { + Release(); + } - success = (det != 0.0f); + void Release() + { + if (texture_buffer) { + glDeleteTextures(1, &texture_buffer); + } + if (offset_buffer) { + glDeleteTextures(1, &offset_buffer); + } + texture_buffer = 0; + offset_buffer = 0; + fvar_width = 0; + channel_offsets.clear(); + } - if (det != 0.0f) { - det = 1.0f / det; - for (a = 0; a < 3; a++) { - for (b = 0; b < 3; b++) { - m1[a][b] *= det; + void Create(const OpenSubdiv::Far::TopologyRefiner *refiner, + const OpenSubdiv::Far::PatchTable *patch_table, + int fvar_width, + const float *fvar_src_data) + { + Release(); + + this->fvar_width = fvar_width; + + /* Expand fvar data to per-patch array */ + const int max_level = refiner->GetMaxLevel(); + const int num_channels = patch_table->GetNumFVarChannels(); + std::vector<float> data; + int fvar_data_offset = 0; + channel_offsets.resize(num_channels); + for (int channel = 0; channel < num_channels; ++channel) { + OpenSubdiv::Far::ConstIndexArray indices = + patch_table->GetFVarValues(channel); + + channel_offsets[channel] = data.size(); + data.reserve(data.size() + indices.size() * fvar_width); + + for (int fvert = 0; fvert < (int)indices.size(); ++fvert) { + int index = indices[fvert] * fvar_width; + for (int i = 0; i < fvar_width; ++i) { + data.push_back(fvar_src_data[fvar_data_offset + index++]); + } + } + if (refiner->IsUniform()) { + const int num_values_max = refiner->GetLevel(max_level).GetNumFVarValues(channel); + fvar_data_offset += num_values_max * fvar_width; + } else { + const int num_values_total = refiner->GetNumFVarValuesTotal(channel); + fvar_data_offset += num_values_total * fvar_width; } } - } - return success; -} + GLuint buffer; + glGenBuffers(1, &buffer); + glBindBuffer(GL_ARRAY_BUFFER, buffer); + glBufferData(GL_ARRAY_BUFFER, data.size()*sizeof(float), + &data[0], GL_STATIC_DRAW); -bool invert_m3(float m[3][3]) -{ - float tmp[3][3]; - bool success; + glGenTextures(1, &texture_buffer); + glBindTexture(GL_TEXTURE_BUFFER, texture_buffer); + glTexBuffer(GL_TEXTURE_BUFFER, GL_R32F, buffer); - success = invert_m3_m3(tmp, m); - copy_m3_m3(m, tmp); + glDeleteBuffers(1, &buffer); - return success; -} + glGenBuffers(1, &buffer); + glBindBuffer(GL_ARRAY_BUFFER, buffer); + glBufferData(GL_ARRAY_BUFFER, channel_offsets.size()*sizeof(int), + &channel_offsets[0], GL_STATIC_DRAW); -void transpose_m3(float mat[3][3]) -{ - float t; - - t = mat[0][1]; - mat[0][1] = mat[1][0]; - mat[1][0] = t; - t = mat[0][2]; - mat[0][2] = mat[2][0]; - mat[2][0] = t; - t = mat[1][2]; - mat[1][2] = mat[2][1]; - mat[2][1] = t; -} + glGenTextures(1, &offset_buffer); + glBindTexture(GL_TEXTURE_BUFFER, offset_buffer); + glTexBuffer(GL_TEXTURE_BUFFER, GL_R32I, buffer); + glBindTexture(GL_TEXTURE_BUFFER, 0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + } + GLuint texture_buffer; + GLuint offset_buffer; + std::vector<int> channel_offsets; + int fvar_width; +}; + +namespace { GLuint compileShader(GLenum shaderType, const char *section, @@ -196,11 +217,14 @@ GLuint compileShader(GLenum shaderType, version, define, sdefine, +#ifdef SUPPORT_COLOR_MATERIAL + "#define SUPPORT_COLOR_MATERIAL\n", +#endif datatoc_gpu_shader_opensubd_display_glsl }; GLuint shader = glCreateShader(shaderType); - glShaderSource(shader, 4, sources, NULL); + glShaderSource(shader, 5, sources, NULL); glCompileShader(shader); GLint status; @@ -295,14 +319,17 @@ GLuint linkProgram(const char *version, const char *define) 0); /* GL_TEXTURE0 */ glProgramUniform1i(program, + glGetUniformLocation(program, "FVarDataOffsetBuffer"), + 30); /* GL_TEXTURE30 */ + + glProgramUniform1i(program, glGetUniformLocation(program, "FVarDataBuffer"), 31); /* GL_TEXTURE31 */ return program; } -void bindProgram(GLMeshInterface * /*mesh*/, - int program) +void bindProgram(OpenSubdiv_GLMesh *gl_mesh, int program) { glUseProgram(program); @@ -346,23 +373,34 @@ void bindProgram(GLMeshInterface * /*mesh*/, glUniform4fv(glGetUniformLocation(program, "diffuse"), 1, color); } - /* TODO(sergey): Bring face varying back. */ -#if 0 /* Face-vertex data */ - if (mesh->GetDrawContext()->GetFvarDataTextureBuffer()) { - glActiveTexture(GL_TEXTURE31); - glBindTexture(GL_TEXTURE_BUFFER, - mesh->GetDrawContext()->GetFvarDataTextureBuffer()); - glActiveTexture(GL_TEXTURE0); - } -#endif + if (gl_mesh->fvar_data != NULL) { + if (gl_mesh->fvar_data->texture_buffer) { + glActiveTexture(GL_TEXTURE31); + glBindTexture(GL_TEXTURE_BUFFER, gl_mesh->fvar_data->texture_buffer); + glActiveTexture(GL_TEXTURE0); + } - /* TODO(sergey): Bring face varying back. */ - glUniform1i(glGetUniformLocation(program, "osd_fvar_count"), - 0/* * mesh->GetFVarCount()*/); + if (gl_mesh->fvar_data->offset_buffer) { + glActiveTexture(GL_TEXTURE30); + glBindTexture(GL_TEXTURE_BUFFER, gl_mesh->fvar_data->offset_buffer); + glActiveTexture(GL_TEXTURE0); + } - glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"), - g_active_uv_index * 2); + glUniform1i(glGetUniformLocation(program, "osd_fvar_count"), + gl_mesh->fvar_data->fvar_width); + if (gl_mesh->fvar_data->channel_offsets.size() > 0 && + g_active_uv_index >= 0) + { + glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"), + gl_mesh->fvar_data->channel_offsets[g_active_uv_index]); + } else { + glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"), 0); + } + } else { + glUniform1i(glGetUniformLocation(program, "osd_fvar_count"), 0); + glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"), 0); + } } } /* namespace */ @@ -390,11 +428,51 @@ bool openSubdiv_osdGLDisplayInit(void) /* minimum supported for OpenSubdiv */ } - g_flat_fill_solid_program = linkProgram(version, "#define FLAT_SHADING\n"); - g_flat_fill_texture2d_program = linkProgram(version, "#define USE_TEXTURE_2D\n#define FLAT_SHADING\n"); - g_smooth_fill_solid_program = linkProgram(version, "#define SMOOTH_SHADING\n"); - g_smooth_fill_texture2d_program = linkProgram(version, "#define USE_TEXTURE_2D\n#define SMOOTH_SHADING\n"); - g_wireframe_program = linkProgram(version, "#define WIREFRAME\n"); + g_flat_fill_solid_program = linkProgram( + version, + "#define USE_COLOR_MATERIAL\n" + "#define USE_LIGHTING\n" + "#define FLAT_SHADING\n"); + g_flat_fill_texture2d_program = linkProgram( + version, + "#define USE_COLOR_MATERIAL\n" + "#define USE_LIGHTING\n" + "#define USE_TEXTURE_2D\n" + "#define FLAT_SHADING\n"); + g_smooth_fill_solid_program = linkProgram( + version, + "#define USE_COLOR_MATERIAL\n" + "#define USE_LIGHTING\n" + "#define SMOOTH_SHADING\n"); + g_smooth_fill_texture2d_program = linkProgram( + version, + "#define USE_COLOR_MATERIAL\n" + "#define USE_LIGHTING\n" + "#define USE_TEXTURE_2D\n" + "#define SMOOTH_SHADING\n"); + + g_flat_fill_solid_shadeless_program = linkProgram( + version, + "#define USE_COLOR_MATERIAL\n" + "#define FLAT_SHADING\n"); + g_flat_fill_texture2d_shadeless_program = linkProgram( + version, + "#define USE_COLOR_MATERIAL\n" + "#define USE_TEXTURE_2D\n" + "#define FLAT_SHADING\n"); + g_smooth_fill_solid_shadeless_program = linkProgram( + version, + "#define USE_COLOR_MATERIAL\n" + "#define SMOOTH_SHADING\n"); + g_smooth_fill_texture2d_shadeless_program = linkProgram( + version, + "#define USE_COLOR_MATERIAL\n" + "#define USE_TEXTURE_2D\n" + "#define SMOOTH_SHADING\n"); + + g_wireframe_program = linkProgram( + version, + "#define WIREFRAME\n"); glGenBuffers(1, &g_lighting_ub); glBindBuffer(GL_UNIFORM_BUFFER, g_lighting_ub); @@ -416,28 +494,31 @@ void openSubdiv_osdGLDisplayDeinit(void) if (g_lighting_ub != 0) { glDeleteBuffers(1, &g_lighting_ub); } - if (g_flat_fill_solid_program) { - glDeleteProgram(g_flat_fill_solid_program); - } - if (g_flat_fill_texture2d_program) { - glDeleteProgram(g_flat_fill_texture2d_program); - } - if (g_smooth_fill_solid_program) { - glDeleteProgram(g_flat_fill_solid_program); - } - if (g_smooth_fill_texture2d_program) { - glDeleteProgram(g_smooth_fill_texture2d_program); - } - if (g_wireframe_program) { - glDeleteProgram(g_wireframe_program); - } +#define SAFE_DELETE_PROGRAM(program) \ + do { \ + if (program) { \ + glDeleteProgram(program); \ + } \ + } while (false) + + SAFE_DELETE_PROGRAM(g_flat_fill_solid_program); + SAFE_DELETE_PROGRAM(g_flat_fill_texture2d_program); + SAFE_DELETE_PROGRAM(g_smooth_fill_solid_program); + SAFE_DELETE_PROGRAM(g_smooth_fill_texture2d_program); + SAFE_DELETE_PROGRAM(g_flat_fill_solid_shadeless_program); + SAFE_DELETE_PROGRAM(g_flat_fill_texture2d_shadeless_program); + SAFE_DELETE_PROGRAM(g_smooth_fill_solid_shadeless_program); + SAFE_DELETE_PROGRAM(g_smooth_fill_texture2d_shadeless_program); + SAFE_DELETE_PROGRAM(g_wireframe_program); + +#undef SAFE_DELETE_PROGRAM } void openSubdiv_osdGLMeshDisplayPrepare(int use_osd_glsl, int active_uv_index) { - g_use_osd_glsl = use_osd_glsl != 0; g_active_uv_index = active_uv_index; + g_use_osd_glsl = (use_osd_glsl != 0); /* Update transformation matrices. */ glGetFloatv(GL_PROJECTION_MATRIX, g_transform.projection_matrix); @@ -494,7 +575,7 @@ void openSubdiv_osdGLMeshDisplayPrepare(int use_osd_glsl, } } -static GLuint prepare_patchDraw(GLMeshInterface *mesh, +static GLuint prepare_patchDraw(OpenSubdiv_GLMesh *gl_mesh, bool fill_quads) { GLint program = 0; @@ -509,51 +590,74 @@ static GLuint prepare_patchDraw(GLMeshInterface *mesh, glUniform1i(location, model == GL_FLAT); } - /* TODO(sergey): Bring this back. */ -#if 0 /* Face-vertex data */ - if (mesh->GetDrawContext()->GetFvarDataTextureBuffer()) { - glActiveTexture(GL_TEXTURE31); - glBindTexture(GL_TEXTURE_BUFFER, - mesh->GetDrawContext()->GetFvarDataTextureBuffer()); - glActiveTexture(GL_TEXTURE0); + if (gl_mesh->fvar_data != NULL) { + if (gl_mesh->fvar_data->texture_buffer) { + glActiveTexture(GL_TEXTURE31); + glBindTexture(GL_TEXTURE_BUFFER, + gl_mesh->fvar_data->texture_buffer); + glActiveTexture(GL_TEXTURE0); + } + + if (gl_mesh->fvar_data->offset_buffer) { + glActiveTexture(GL_TEXTURE30); + glBindTexture(GL_TEXTURE_BUFFER, + gl_mesh->fvar_data->offset_buffer); + glActiveTexture(GL_TEXTURE0); + } GLint location = glGetUniformLocation(program, "osd_fvar_count"); if (location != -1) { - glUniform1i(location, mesh->GetFVarCount()); + glUniform1i(location, gl_mesh->fvar_data->fvar_width); } location = glGetUniformLocation(program, "osd_active_uv_offset"); if (location != -1) { - glUniform1i(location, - g_active_uv_index * 2); + if (gl_mesh->fvar_data->channel_offsets.size() > 0 && + g_active_uv_index >= 0) + { + glUniform1i(location, + gl_mesh->fvar_data->channel_offsets[g_active_uv_index]); + } else { + glUniform1i(location, 0); + } } + } else { + glUniform1i(glGetUniformLocation(program, "osd_fvar_count"), 0); + glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"), 0); } -#endif - } return program; } if (fill_quads) { int model; - GLboolean use_texture_2d; + GLboolean use_texture_2d, use_lighting; glGetIntegerv(GL_SHADE_MODEL, &model); glGetBooleanv(GL_TEXTURE_2D, &use_texture_2d); + glGetBooleanv(GL_LIGHTING, &use_lighting); if (model == GL_FLAT) { if (use_texture_2d) { - program = g_flat_fill_texture2d_program; + program = use_lighting + ? g_flat_fill_texture2d_program + : g_flat_fill_texture2d_shadeless_program; } else { - program = g_flat_fill_solid_program; + program = use_lighting + ? g_flat_fill_solid_program + : g_flat_fill_solid_shadeless_program; } } else { if (use_texture_2d) { - program = g_smooth_fill_texture2d_program; + program = use_lighting + ? g_smooth_fill_texture2d_program + : g_smooth_fill_texture2d_shadeless_program; } else { - program = g_smooth_fill_solid_program; + program = use_lighting + ? g_smooth_fill_solid_program + : g_smooth_fill_solid_shadeless_program; } } } @@ -562,7 +666,7 @@ static GLuint prepare_patchDraw(GLMeshInterface *mesh, program = g_wireframe_program; } - bindProgram(mesh, program); + bindProgram(gl_mesh, program); return program; } @@ -623,7 +727,7 @@ static void draw_partition_patches_range(GLMeshInterface *mesh, const int num_draw_patches = std::min(num_remained_patches, num_block_patches - start_draw_patch); perform_drawElements(program, - i, + i + start_draw_patch, num_draw_patches * num_control_verts, patch.GetIndexBase() + start_draw_patch * num_control_verts); num_remained_patches -= num_draw_patches; @@ -669,7 +773,7 @@ void openSubdiv_osdGLMeshDisplay(OpenSubdiv_GLMesh *gl_mesh, } /* Setup GLSL/OpenGL to draw patches in current context. */ - GLuint program = prepare_patchDraw(mesh, fill_quads != 0); + GLuint program = prepare_patchDraw(gl_mesh, fill_quads != 0); if (start_patch != -1) { draw_partition_patches_range(mesh, @@ -684,3 +788,23 @@ void openSubdiv_osdGLMeshDisplay(OpenSubdiv_GLMesh *gl_mesh, /* Finish patch drawing by restoring all changes to the OpenGL context. */ finish_patchDraw(fill_quads != 0); } + +void openSubdiv_osdGLAllocFVar(OpenSubdiv_TopologyRefinerDescr *topology_refiner, + OpenSubdiv_GLMesh *gl_mesh, + const float *fvar_data) +{ + GLMeshInterface *mesh = + (GLMeshInterface *)(gl_mesh->descriptor); + gl_mesh->fvar_data = OBJECT_GUARDED_NEW(OpenSubdiv_GLMeshFVarData); + gl_mesh->fvar_data->Create(topology_refiner->osd_refiner, + mesh->GetFarPatchTable(), + 2, + fvar_data); +} + +void openSubdiv_osdGLDestroyFVar(OpenSubdiv_GLMesh *gl_mesh) +{ + if (gl_mesh->fvar_data != NULL) { + OBJECT_GUARDED_DELETE(gl_mesh->fvar_data, OpenSubdiv_GLMeshFVarData); + } +} |