diff options
Diffstat (limited to 'source/blender/gpu')
-rw-r--r-- | source/blender/gpu/GPU_extensions.h | 18 | ||||
-rw-r--r-- | source/blender/gpu/GPU_material.h | 5 | ||||
-rw-r--r-- | source/blender/gpu/SConscript | 3 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_buffers.c | 92 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_codegen.c | 16 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_compositing.c | 13 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_debug.c | 44 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_draw.c | 14 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_extensions.c | 293 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_init_exit.c | 2 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_material.c | 40 | ||||
-rw-r--r-- | source/blender/gpu/shaders/gpu_shader_material.glsl | 23 |
12 files changed, 420 insertions, 143 deletions
diff --git a/source/blender/gpu/GPU_extensions.h b/source/blender/gpu/GPU_extensions.h index f3927ba960b..685ae59c47b 100644 --- a/source/blender/gpu/GPU_extensions.h +++ b/source/blender/gpu/GPU_extensions.h @@ -130,6 +130,8 @@ GPUTexture *GPU_texture_create_depth(int w, int h, char err_out[256]); GPUTexture *GPU_texture_create_vsm_shadow_map(int size, char err_out[256]); GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, bool repeat, char err_out[256]); GPUTexture *GPU_texture_create_1D_procedural(int w, const float *pixels, char err_out[256]); +GPUTexture *GPU_texture_create_2D_multisample(int w, int h, const float *pixels, GPUHDRType hdr, int samples, char err_out[256]); +GPUTexture *GPU_texture_create_depth_multisample(int w, int h, int samples, char err_out[256]); GPUTexture *GPU_texture_from_blender(struct Image *ima, struct ImageUser *iuser, bool is_data, double time, int mipmap); GPUTexture *GPU_texture_from_preview(struct PreviewImage *prv, int mipmap); @@ -179,13 +181,14 @@ void GPU_framebuffer_blur(GPUFrameBuffer *fb, GPUTexture *tex, GPUFrameBuffer *b * - wrapper around framebuffer and texture for simple offscreen drawing * - changes size if graphics card can't support it */ -GPUOffScreen *GPU_offscreen_create(int width, int height, char err_out[256]); +GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, char err_out[256]); void GPU_offscreen_free(GPUOffScreen *ofs); void GPU_offscreen_bind(GPUOffScreen *ofs, bool save); void GPU_offscreen_unbind(GPUOffScreen *ofs, bool restore); void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels); int GPU_offscreen_width(const GPUOffScreen *ofs); int GPU_offscreen_height(const GPUOffScreen *ofs); +int GPU_offscreen_color_texture(const GPUOffScreen *ofs); /* Builtin/Non-generated shaders */ typedef enum GPUProgramType { @@ -204,6 +207,19 @@ void GPU_program_unbind(GPUProgram *); * - must call texture bind before setting a texture as uniform! */ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const char *geocode, const char *libcode, const char *defines, int input, int output, int number); +enum { + GPU_SHADER_FLAGS_NONE = 0, + GPU_SHADER_FLAGS_SPECIAL_OPENSUBDIV = (1 << 0), +}; +GPUShader *GPU_shader_create_ex(const char *vertexcode, + const char *fragcode, + const char *geocode, + const char *libcode, + const char *defines, + int input, + int output, + int number, + const int flags); void GPU_shader_free(GPUShader *shader); void GPU_shader_bind(GPUShader *shader); diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h index dd08ed83e5a..25a4f33b526 100644 --- a/source/blender/gpu/GPU_material.h +++ b/source/blender/gpu/GPU_material.h @@ -160,6 +160,7 @@ typedef enum GPUDynamicType { GPU_DYNAMIC_LAMP_ATT2 = 9 | GPU_DYNAMIC_GROUP_LAMP, GPU_DYNAMIC_LAMP_SPOTSIZE = 10 | GPU_DYNAMIC_GROUP_LAMP, GPU_DYNAMIC_LAMP_SPOTBLEND = 11 | GPU_DYNAMIC_GROUP_LAMP, + GPU_DYNAMIC_LAMP_SPOTSCALE = 12 | GPU_DYNAMIC_GROUP_LAMP, GPU_DYNAMIC_SAMPLER_2DBUFFER = 1 | GPU_DYNAMIC_GROUP_SAMPLER, GPU_DYNAMIC_SAMPLER_2DIMAGE = 2 | GPU_DYNAMIC_GROUP_SAMPLER, @@ -314,13 +315,13 @@ void GPU_mist_update_values(int type, float start, float dist, float inten, floa void GPU_horizon_update_color(float color[3]); void GPU_ambient_update_color(float color[3]); -typedef struct GPUParticleInfo +struct GPUParticleInfo { float scalprops[4]; float location[3]; float velocity[3]; float angular_velocity[3]; -} GPUParticleInfo; +}; #ifdef WITH_OPENSUBDIV struct DerivedMesh; diff --git a/source/blender/gpu/SConscript b/source/blender/gpu/SConscript index 880a6d14e26..d27d5b09b56 100644 --- a/source/blender/gpu/SConscript +++ b/source/blender/gpu/SConscript @@ -30,7 +30,8 @@ Import ('env') sources = env.Glob('intern/*.c') sources += env.Glob('shaders/*.c') -defs = env['BF_GL_DEFINITIONS'] +defs = [] +defs += env['BF_GL_DEFINITIONS'] incs = [ '.', diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index 2e1b866a160..b4617b9790e 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -95,8 +95,6 @@ const GPUBufferTypeSettings gpu_buffer_type_settings[] = { {GL_ELEMENT_ARRAY_BUFFER_ARB, 4}, /* triangles, 1 point since we are allocating from tottriangle points, which account for all points */ {GL_ELEMENT_ARRAY_BUFFER_ARB, 1}, - /* fast triangles */ - {GL_ELEMENT_ARRAY_BUFFER_ARB, 1}, }; #define MAX_GPU_ATTRIB_DATA 32 @@ -1121,6 +1119,9 @@ struct GPU_PBVH_Buffers { GPUBuffer *vert_buf, *index_buf, *index_buf_fast; GLenum index_type; + int *baseelemarray; + void **baseindex; + /* mesh pointers in case buffer allocation fails */ const MPoly *mpoly; const MLoop *mloop; @@ -1607,26 +1608,26 @@ static GPUBuffer *gpu_get_grid_buffer(int gridsize, GLenum *index_type, unsigned #define FILL_FAST_BUFFER(type_) \ { \ - type_ *buffer; \ - buffers->index_buf_fast = GPU_buffer_alloc(sizeof(type_) * 6 * totgrid, false); \ - buffer = GPU_buffer_lock(buffers->index_buf_fast, GPU_BINDING_INDEX); \ - if (buffer) { \ - int i; \ - for (i = 0; i < totgrid; i++) { \ - int currentquad = i * 6; \ - buffer[currentquad] = i * gridsize * gridsize; \ - buffer[currentquad + 1] = i * gridsize * gridsize + gridsize - 1; \ - buffer[currentquad + 2] = (i + 1) * gridsize * gridsize - gridsize; \ - buffer[currentquad + 3] = (i + 1) * gridsize * gridsize - 1; \ - buffer[currentquad + 4] = i * gridsize * gridsize + gridsize - 1; \ - buffer[currentquad + 5] = (i + 1) * gridsize * gridsize - gridsize; \ - } \ - GPU_buffer_unlock(buffers->index_buf_fast, GPU_BINDING_INDEX); \ + type_ *buffer; \ + buffers->index_buf_fast = GPU_buffer_alloc(sizeof(type_) * 6 * totgrid, false); \ + buffer = GPU_buffer_lock(buffers->index_buf_fast, GPU_BINDING_INDEX); \ + if (buffer) { \ + int i; \ + for (i = 0; i < totgrid; i++) { \ + int currentquad = i * 6; \ + buffer[currentquad] = i * gridsize * gridsize + gridsize - 1; \ + buffer[currentquad + 1] = i * gridsize * gridsize; \ + buffer[currentquad + 2] = (i + 1) * gridsize * gridsize - gridsize; \ + buffer[currentquad + 3] = (i + 1) * gridsize * gridsize - 1; \ + buffer[currentquad + 4] = i * gridsize * gridsize + gridsize - 1; \ + buffer[currentquad + 5] = (i + 1) * gridsize * gridsize - gridsize; \ + } \ + GPU_buffer_unlock(buffers->index_buf_fast, GPU_BINDING_INDEX); \ } \ else { \ - GPU_buffer_free(buffers->index_buf_fast); \ - buffers->index_buf_fast = NULL; \ - } \ + GPU_buffer_free(buffers->index_buf_fast); \ + buffers->index_buf_fast = NULL; \ + } \ } (void)0 GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers(int *grid_indices, int totgrid, @@ -1681,6 +1682,18 @@ GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers(int *grid_indices, int totgrid, if (buffers->index_buf) buffers->vert_buf = GPU_buffer_alloc(sizeof(VertexBufferFormat) * totgrid * key->grid_area, false); + if (GLEW_ARB_draw_elements_base_vertex) { + int i; + buffers->baseelemarray = MEM_mallocN(sizeof(int) * totgrid * 2, "GPU_PBVH_Buffers.baseelemarray"); + buffers->baseindex = MEM_mallocN(sizeof(void *) * totgrid, "GPU_PBVH_Buffers.baseindex"); + for (i = 0; i < totgrid; i++) { + buffers->baseelemarray[i] = buffers->tot_quad * 6; + buffers->baseelemarray[i + totgrid] = i * key->grid_area; + buffers->baseindex[i] = buffers->index_buf && !buffers->index_buf->use_vbo ? + buffers->index_buf->pointer : NULL; + } + } + return buffers; } @@ -2012,21 +2025,40 @@ void GPU_draw_pbvh_buffers(GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial, if (buffers->tot_quad) { const char *offset = base; - int i, last = buffers->has_hidden ? 1 : buffers->totgrid; - for (i = 0; i < last; i++) { + const bool drawall = !(buffers->has_hidden || do_fast); + + if (GLEW_ARB_draw_elements_base_vertex && drawall) { + glVertexPointer(3, GL_FLOAT, sizeof(VertexBufferFormat), offset + offsetof(VertexBufferFormat, co)); glNormalPointer(GL_SHORT, sizeof(VertexBufferFormat), offset + offsetof(VertexBufferFormat, no)); glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(VertexBufferFormat), offset + offsetof(VertexBufferFormat, color)); - - if (do_fast) - glDrawElements(GL_TRIANGLES, buffers->totgrid * 6, buffers->index_type, index_base); - else - glDrawElements(GL_TRIANGLES, buffers->tot_quad * 6, buffers->index_type, index_base); - offset += buffers->gridkey.grid_area * sizeof(VertexBufferFormat); + glMultiDrawElementsBaseVertex(GL_TRIANGLES, buffers->baseelemarray, buffers->index_type, + (const void * const *)buffers->baseindex, + buffers->totgrid, &buffers->baseelemarray[buffers->totgrid]); + } + else { + int i, last = drawall ? buffers->totgrid : 1; + + /* we could optimize this to one draw call, but it would need more memory */ + for (i = 0; i < last; i++) { + glVertexPointer(3, GL_FLOAT, sizeof(VertexBufferFormat), + offset + offsetof(VertexBufferFormat, co)); + glNormalPointer(GL_SHORT, sizeof(VertexBufferFormat), + offset + offsetof(VertexBufferFormat, no)); + glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(VertexBufferFormat), + offset + offsetof(VertexBufferFormat, color)); + + if (do_fast) + glDrawElements(GL_TRIANGLES, buffers->totgrid * 6, buffers->index_type, index_base); + else + glDrawElements(GL_TRIANGLES, buffers->tot_quad * 6, buffers->index_type, index_base); + + offset += buffers->gridkey.grid_area * sizeof(VertexBufferFormat); + } } } else if (buffers->tot_tri) { @@ -2112,6 +2144,10 @@ void GPU_free_pbvh_buffers(GPU_PBVH_Buffers *buffers) GPU_buffer_free(buffers->index_buf); if (buffers->index_buf_fast) GPU_buffer_free(buffers->index_buf_fast); + if (buffers->baseelemarray) + MEM_freeN(buffers->baseelemarray); + if (buffers->baseindex) + MEM_freeN(buffers->baseindex); MEM_freeN(buffers); } diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index 68b9e3845f7..496302bb44e 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -718,7 +718,7 @@ static char *code_generate_vertex(ListBase *nodes, const GPUMatType type) GPUNode *node; GPUInput *input; char *code; - char *vertcode; + char *vertcode = NULL; for (node = nodes->first; node; node = node->next) { for (input = node->inputs.first; input; input = input->next) { @@ -839,6 +839,8 @@ static char *code_generate_geometry(ListBase *nodes, bool use_opensubdiv) BLI_dynstr_append(ds, datatoc_gpu_shader_geometry_glsl); /* Generate varying assignments. */ + /* TODO(sergey): Disabled for now, needs revisit. */ +#if 0 for (node = nodes->first; node; node = node->next) { for (input = node->inputs.first; input; input = input->next) { if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) { @@ -852,6 +854,7 @@ static char *code_generate_geometry(ListBase *nodes, bool use_opensubdiv) } } } +#endif BLI_dynstr_append(ds, "}\n\n"); code = BLI_dynstr_get_cstring(ds); @@ -1612,7 +1615,16 @@ GPUPass *GPU_generate_pass(ListBase *nodes, GPUNodeLink *outlink, fragmentcode = code_generate_fragment(nodes, outlink->output); vertexcode = code_generate_vertex(nodes, type); geometrycode = code_generate_geometry(nodes, use_opensubdiv); - shader = GPU_shader_create(vertexcode, fragmentcode, geometrycode, glsl_material_library, NULL, 0, 0, 0); + shader = GPU_shader_create_ex(vertexcode, + fragmentcode, + geometrycode, + glsl_material_library, + NULL, + 0, + 0, + 0, + use_opensubdiv ? GPU_SHADER_FLAGS_SPECIAL_OPENSUBDIV + : GPU_SHADER_FLAGS_NONE); /* failed? */ if (!shader) { diff --git a/source/blender/gpu/intern/gpu_compositing.c b/source/blender/gpu/intern/gpu_compositing.c index 2bafee0fb52..da5db73d382 100644 --- a/source/blender/gpu/intern/gpu_compositing.c +++ b/source/blender/gpu/intern/gpu_compositing.c @@ -306,6 +306,9 @@ bool GPU_fx_compositor_initialize_passes( fx->effects = 0; + if (!GPU_non_power_of_two_support() || !GLEW_EXT_framebuffer_object || !GLEW_ARB_fragment_shader) + return false; + if (!fx_settings) { cleanup_fx_gl_data(fx, true); return false; @@ -340,16 +343,18 @@ bool GPU_fx_compositor_initialize_passes( if (fx_flag & GPU_FX_FLAG_SSAO) num_passes++; - if (!fx->gbuffer) + if (!fx->gbuffer) { fx->gbuffer = GPU_framebuffer_create(); + if (!fx->gbuffer) { + return false; + } + } + /* try creating the jitter texture */ if (!fx->jitter_buffer) fx->jitter_buffer = create_jitter_texture(); - if (!fx->gbuffer) - return false; - /* check if color buffers need recreation */ if (!fx->color_buffer || !fx->depth_buffer || w != fx->gbuffer_dim[0] || h != fx->gbuffer_dim[1]) { cleanup_fx_gl_data(fx, false); diff --git a/source/blender/gpu/intern/gpu_debug.c b/source/blender/gpu/intern/gpu_debug.c index 15fe6edb2de..29b7ff11586 100644 --- a/source/blender/gpu/intern/gpu_debug.c +++ b/source/blender/gpu/intern/gpu_debug.c @@ -43,7 +43,7 @@ #define CASE_CODE_RETURN_STR(code) case code: return #code; -static const char* gpu_gl_error_symbol(GLenum err) +static const char *gpu_gl_error_symbol(GLenum err) { switch (err) { CASE_CODE_RETURN_STR(GL_NO_ERROR) @@ -81,8 +81,8 @@ static bool gpu_report_gl_errors(const char *file, int line, const char *str) } else { /* glGetError should have cleared the error flag, so if we get the - same flag twice that means glGetError itself probably triggered - the error. This happens on Windows if the GL context is invalid. + * same flag twice that means glGetError itself probably triggered + * the error. This happens on Windows if the GL context is invalid. */ { GLenum new_error = glGetError(); @@ -92,22 +92,18 @@ static bool gpu_report_gl_errors(const char *file, int line, const char *str) } } - fprintf( - stderr, - "%s(%d): ``%s'' -> GL Error (0x%04X - %s): %s\n", - file, - line, - str, - gl_error, - gpu_gl_error_symbol(gl_error), - gpuErrorString(gl_error)); + fprintf(stderr, + "%s:%d: ``%s'' -> GL Error (0x%04X - %s): %s\n", + file, line, str, gl_error, + gpu_gl_error_symbol(gl_error), + gpuErrorString(gl_error)); return false; } } -const char* gpuErrorString(GLenum err) +const char *gpuErrorString(GLenum err) { switch (err) { case GL_NO_ERROR: @@ -163,9 +159,10 @@ const char* gpuErrorString(GLenum err) #endif -static void APIENTRY gpu_debug_proc(GLenum source, GLenum type, GLuint UNUSED(id), - GLenum UNUSED(severity), GLsizei UNUSED(length), - const GLchar *message, GLvoid *UNUSED(userParm)) +static void APIENTRY gpu_debug_proc( + GLenum source, GLenum type, GLuint UNUSED(id), + GLenum UNUSED(severity), GLsizei UNUSED(length), + const GLchar *message, const GLvoid *UNUSED(userParm)) { if (source == GL_DEBUG_SOURCE_API && type == GL_DEBUG_TYPE_ERROR) { fprintf(stderr, "GL: %s\n", message); @@ -179,9 +176,10 @@ static void APIENTRY gpu_debug_proc(GLenum source, GLenum type, GLuint UNUSED(id #ifndef GLEW_ES_ONLY -static void APIENTRY gpu_debug_proc_amd(GLuint UNUSED(id), GLenum UNUSED(category), - GLenum UNUSED(severity), GLsizei UNUSED(length), - const GLchar *message, GLvoid *UNUSED(userParm)) +static void APIENTRY gpu_debug_proc_amd( + GLuint UNUSED(id), GLenum UNUSED(category), + GLenum UNUSED(severity), GLsizei UNUSED(length), + const GLchar *message, GLvoid *UNUSED(userParm)) { fprintf(stderr, "GL: %s\n", message); } @@ -206,9 +204,9 @@ void gpu_debug_init(void) if (GLEW_KHR_debug) { #ifndef GLEW_ES_ONLY - glDebugMessageCallback(gpu_debug_proc, mxGetCurrentContext()); - glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE); - GPU_string_marker(sizeof(success), success); + glDebugMessageCallback(gpu_debug_proc, mxGetCurrentContext()); + glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE); + GPU_string_marker(sizeof(success), success); #endif return; } @@ -322,7 +320,7 @@ void GPU_print_error_debug(const char *str) } -void GPU_assert_no_gl_errors(const char* file, int line, const char* str) +void GPU_assert_no_gl_errors(const char *file, int line, const char *str) { if (G.debug) { GLboolean gl_ok = gpu_report_gl_errors(file, line, str); diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index af8b2a0f806..bf7b8fbc386 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -1533,11 +1533,15 @@ void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, O #ifdef WITH_OPENSUBDIV { DerivedMesh *derivedFinal = NULL; - Mesh *me = ob->data; - BMEditMesh *em = me->edit_btmesh; - - if (em != NULL) { - derivedFinal = em->derivedFinal; + if (ob->type == OB_MESH) { + Mesh *me = ob->data; + BMEditMesh *em = me->edit_btmesh; + if (em != NULL) { + derivedFinal = em->derivedFinal; + } + else { + derivedFinal = ob->derivedFinal; + } } else { derivedFinal = ob->derivedFinal; diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c index ca9b4225faa..e1dff03d500 100644 --- a/source/blender/gpu/intern/gpu_extensions.c +++ b/source/blender/gpu/intern/gpu_extensions.c @@ -110,6 +110,7 @@ static struct GPUGlobal { int glslsupport; int extdisabled; int colordepth; + int samples_color_texture_max; int npotdisabled; /* ATI 3xx-5xx (and more) chipsets support NPoT partially (== not enough) */ int dlistsdisabled; /* Legacy ATI driver does not support display lists well */ GPUDeviceType device; @@ -180,6 +181,10 @@ void gpu_extensions_init(void) glGetIntegerv(GL_BLUE_BITS, &b); GG.colordepth = r + g + b; /* assumes same depth for RGB */ + if (GLEW_ARB_texture_multisample) { + glGetIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES , &GG.samples_color_texture_max); + } + vendor = (const char *)glGetString(GL_VENDOR); renderer = (const char *)glGetString(GL_RENDERER); version = (const char *)glGetString(GL_VERSION); @@ -380,15 +385,18 @@ static void GPU_print_framebuffer_error(GLenum status, char err_out[256]) struct GPUTexture { int w, h; /* width/height */ + int w_orig, h_orig; /* width/height (before power of 2 is applied) */ int number; /* number for multitexture binding */ int refcount; /* reference count */ GLenum target; /* GL_TEXTURE_* */ + GLenum target_base; /* same as target, (but no multisample) */ GLuint bindcode; /* opengl identifier for texture */ int fromblender; /* we got the texture from Blender */ GPUFrameBuffer *fb; /* GPUFramebuffer this texture is attached to */ int fb_attachment; /* slot the texture is attached to */ int depth; /* is a depth texture? if 3D how deep? */ + int depth_orig; /* depth (before power of 2 is applied) */ }; static unsigned char *GPU_texture_convert_pixels(int length, const float *fpixels) @@ -419,7 +427,8 @@ static void GPU_glTexSubImageEmpty(GLenum target, GLenum format, int x, int y, i } static GPUTexture *GPU_texture_create_nD( - int w, int h, int n, const float *fpixels, int depth, GPUHDRType hdr_type, int components, + int w, int h, int n, const float *fpixels, int depth, + GPUHDRType hdr_type, int components, int samples, char err_out[256]) { GPUTexture *tex; @@ -429,13 +438,18 @@ static GPUTexture *GPU_texture_create_nD( if (depth && !GLEW_ARB_depth_texture) return NULL; + if (samples) { + CLAMP_MAX(samples, GG.samples_color_texture_max); + } + tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); - tex->w = w; - tex->h = h; + tex->w = tex->w_orig = w; + tex->h = tex->h_orig = h; tex->number = -1; tex->refcount = 1; - tex->target = (n == 1)? GL_TEXTURE_1D: GL_TEXTURE_2D; - tex->depth = depth; + tex->target = (n == 1) ? GL_TEXTURE_1D : (samples ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D); + tex->target_base = (n == 1) ? GL_TEXTURE_1D : GL_TEXTURE_2D; + tex->depth = tex->depth_orig = depth; tex->fb_attachment = -1; glGenTextures(1, &tex->bindcode); @@ -521,8 +535,13 @@ static GPUTexture *GPU_texture_create_nD( } } else { - glTexImage2D(tex->target, 0, internalformat, tex->w, tex->h, 0, - format, type, NULL); + if (samples) { + glTexImage2DMultisample(tex->target, samples, internalformat, tex->w, tex->h, true); + } + else { + glTexImage2D(tex->target, 0, internalformat, tex->w, tex->h, 0, + format, type, NULL); + } if (fpixels) { glTexSubImage2D(tex->target, 0, 0, 0, w, h, @@ -539,23 +558,23 @@ static GPUTexture *GPU_texture_create_nD( MEM_freeN(pixels); if (depth) { - glTexParameteri(tex->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(tex->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(tex->target, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE); - glTexParameteri(tex->target, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL); - glTexParameteri(tex->target, GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY); + glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE); + glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL); + glTexParameteri(tex->target_base, GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY); } else { - glTexParameteri(tex->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(tex->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } - if (tex->target != GL_TEXTURE_1D) { - glTexParameteri(tex->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(tex->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + if (tex->target_base != GL_TEXTURE_1D) { + glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } else - glTexParameteri(tex->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); return tex; } @@ -573,12 +592,13 @@ GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, const f return NULL; tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); - tex->w = w; - tex->h = h; - tex->depth = depth; + tex->w = tex->w_orig = w; + tex->h = tex->h_orig = h; + tex->depth = tex->depth_orig = depth; tex->number = -1; tex->refcount = 1; tex->target = GL_TEXTURE_3D; + tex->target_base = GL_TEXTURE_3D; glGenTextures(1, &tex->bindcode); @@ -725,6 +745,7 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, bool is_data, tex->number = -1; tex->refcount = 1; tex->target = GL_TEXTURE_2D; + tex->target_base = GL_TEXTURE_2D; tex->fromblender = 1; ima->gputexture= tex; @@ -738,8 +759,8 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, bool is_data, glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h); glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_BORDER, &border); - tex->w = w - border; - tex->h = h - border; + tex->w = tex->w_orig = w - border; + tex->h = tex->h_orig = h - border; } glBindTexture(GL_TEXTURE_2D, lastbindcode); @@ -773,6 +794,7 @@ GPUTexture *GPU_texture_from_preview(PreviewImage *prv, int mipmap) tex->number = -1; tex->refcount = 1; tex->target = GL_TEXTURE_2D; + tex->target_base = GL_TEXTURE_2D; prv->gputexture[0] = tex; @@ -784,8 +806,8 @@ GPUTexture *GPU_texture_from_preview(PreviewImage *prv, int mipmap) glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w); glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h); - tex->w = w; - tex->h = h; + tex->w = tex->w_orig = w; + tex->h = tex->h_orig = h; } glBindTexture(GL_TEXTURE_2D, lastbindcode); @@ -796,7 +818,7 @@ GPUTexture *GPU_texture_from_preview(PreviewImage *prv, int mipmap) GPUTexture *GPU_texture_create_1D(int w, const float *fpixels, char err_out[256]) { - GPUTexture *tex = GPU_texture_create_nD(w, 1, 1, fpixels, 0, GPU_HDR_NONE, 4, err_out); + GPUTexture *tex = GPU_texture_create_nD(w, 1, 1, fpixels, 0, GPU_HDR_NONE, 4, 0, err_out); if (tex) GPU_texture_unbind(tex); @@ -806,30 +828,48 @@ GPUTexture *GPU_texture_create_1D(int w, const float *fpixels, char err_out[256] GPUTexture *GPU_texture_create_2D(int w, int h, const float *fpixels, GPUHDRType hdr, char err_out[256]) { - GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, 0, hdr, 4, err_out); + GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, 0, hdr, 4, 0, err_out); if (tex) GPU_texture_unbind(tex); return tex; } +GPUTexture *GPU_texture_create_2D_multisample(int w, int h, const float *fpixels, GPUHDRType hdr, int samples, char err_out[256]) +{ + GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, 0, hdr, 4, samples, err_out); + + if (tex) + GPU_texture_unbind(tex); + + return tex; +} GPUTexture *GPU_texture_create_depth(int w, int h, char err_out[256]) { - GPUTexture *tex = GPU_texture_create_nD(w, h, 2, NULL, 1, GPU_HDR_NONE, 1, err_out); + GPUTexture *tex = GPU_texture_create_nD(w, h, 2, NULL, 1, GPU_HDR_NONE, 1, 0, err_out); if (tex) GPU_texture_unbind(tex); return tex; } +GPUTexture *GPU_texture_create_depth_multisample(int w, int h, int samples, char err_out[256]) +{ + GPUTexture *tex = GPU_texture_create_nD(w, h, 2, NULL, 1, GPU_HDR_NONE, 1, samples, err_out); + + if (tex) + GPU_texture_unbind(tex); + + return tex; +} /** * A shadow map for VSM needs two components (depth and depth^2) */ GPUTexture *GPU_texture_create_vsm_shadow_map(int size, char err_out[256]) { - GPUTexture *tex = GPU_texture_create_nD(size, size, 2, NULL, 0, GPU_HDR_FULL_FLOAT, 2, err_out); + GPUTexture *tex = GPU_texture_create_nD(size, size, 2, NULL, 0, GPU_HDR_FULL_FLOAT, 2, 0, err_out); if (tex) { /* Now we tweak some of the settings */ @@ -844,7 +884,7 @@ GPUTexture *GPU_texture_create_vsm_shadow_map(int size, char err_out[256]) GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, bool repeat, char err_out[256]) { - GPUTexture *tex = GPU_texture_create_nD(w, h, 2, pixels, 0, GPU_HDR_HALF_FLOAT, 2, err_out); + GPUTexture *tex = GPU_texture_create_nD(w, h, 2, pixels, 0, GPU_HDR_HALF_FLOAT, 2, 0, err_out); if (tex) { /* Now we tweak some of the settings */ @@ -863,7 +903,7 @@ GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, GPUTexture *GPU_texture_create_1D_procedural(int w, const float *pixels, char err_out[256]) { - GPUTexture *tex = GPU_texture_create_nD(w, 0, 1, pixels, 0, GPU_HDR_HALF_FLOAT, 2, err_out); + GPUTexture *tex = GPU_texture_create_nD(w, 0, 1, pixels, 0, GPU_HDR_HALF_FLOAT, 2, 0, err_out); if (tex) { /* Now we tweak some of the settings */ @@ -963,7 +1003,7 @@ void GPU_texture_unbind(GPUTexture *tex) arbnumber = (GLenum)((GLuint)GL_TEXTURE0_ARB + tex->number); if (tex->number != 0) glActiveTextureARB(arbnumber); glBindTexture(tex->target, 0); - glDisable(tex->target); + glDisable(tex->target_base); if (tex->number != 0) glActiveTextureARB(GL_TEXTURE0_ARB); tex->number = -1; @@ -1187,8 +1227,12 @@ void GPU_texture_bind_as_framebuffer(GPUTexture *tex) glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + tex->fb_attachment); } + if (tex->target == GL_TEXTURE_2D_MULTISAMPLE) { + glEnable(GL_MULTISAMPLE_ARB); + } + /* push matrices and set default viewport and matrix */ - glViewport(0, 0, tex->w, tex->h); + glViewport(0, 0, tex->w_orig, tex->h_orig); GG.currentfb = tex->fb->object; glMatrixMode(GL_PROJECTION); @@ -1226,7 +1270,7 @@ void GPU_framebuffer_slots_bind(GPUFrameBuffer *fb, int slot) glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + slot); /* push matrices and set default viewport and matrix */ - glViewport(0, 0, fb->colortex[slot]->w, fb->colortex[slot]->h); + glViewport(0, 0, fb->colortex[slot]->w_orig, fb->colortex[slot]->h_orig); GG.currentfb = fb->object; glMatrixMode(GL_PROJECTION); @@ -1256,7 +1300,7 @@ void GPU_framebuffer_bind_no_save(GPUFrameBuffer *fb, int slot) glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + slot); /* push matrices and set default viewport and matrix */ - glViewport(0, 0, fb->colortex[slot]->w, fb->colortex[slot]->h); + glViewport(0, 0, fb->colortex[slot]->w_orig, fb->colortex[slot]->h_orig); GG.currentfb = fb->object; GG.currentfb = fb->object; } @@ -1316,8 +1360,8 @@ void GPU_framebuffer_restore(void) void GPU_framebuffer_blur(GPUFrameBuffer *fb, GPUTexture *tex, GPUFrameBuffer *blurfb, GPUTexture *blurtex) { - const float scaleh[2] = {1.0f / GPU_texture_opengl_width(blurtex), 0.0f}; - const float scalev[2] = {0.0f, 1.0f / GPU_texture_opengl_height(tex)}; + const float scaleh[2] = {1.0f / blurtex->w_orig, 0.0f}; + const float scalev[2] = {0.0f, 1.0f / tex->h_orig}; GPUShader *blur_shader = GPU_shader_get_builtin_shader(GPU_SHADER_SEP_GAUSSIAN_BLUR); int scale_uniform, texture_source_uniform; @@ -1341,7 +1385,7 @@ void GPU_framebuffer_blur(GPUFrameBuffer *fb, GPUTexture *tex, GPUFrameBuffer *b GPU_shader_bind(blur_shader); GPU_shader_uniform_vector(blur_shader, scale_uniform, 2, 1, scaleh); GPU_shader_uniform_texture(blur_shader, texture_source_uniform, tex); - glViewport(0, 0, GPU_texture_opengl_width(blurtex), GPU_texture_opengl_height(blurtex)); + glViewport(0, 0, blurtex->w_orig, blurtex->h_orig); /* Peparing to draw quad */ glMatrixMode(GL_MODELVIEW); @@ -1370,7 +1414,7 @@ void GPU_framebuffer_blur(GPUFrameBuffer *fb, GPUTexture *tex, GPUFrameBuffer *b GG.currentfb = fb->object; - glViewport(0, 0, GPU_texture_opengl_width(tex), GPU_texture_opengl_height(tex)); + glViewport(0, 0, tex->w_orig, tex->h_orig); GPU_shader_uniform_vector(blur_shader, scale_uniform, 2, 1, scalev); GPU_shader_uniform_texture(blur_shader, texture_source_uniform, blurtex); GPU_texture_bind(blurtex, 0); @@ -1393,7 +1437,7 @@ struct GPUOffScreen { GPUTexture *depth; }; -GPUOffScreen *GPU_offscreen_create(int width, int height, char err_out[256]) +GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, char err_out[256]) { GPUOffScreen *ofs; @@ -1405,7 +1449,22 @@ GPUOffScreen *GPU_offscreen_create(int width, int height, char err_out[256]) return NULL; } - ofs->depth = GPU_texture_create_depth(width, height, err_out); + if (samples) { + if (!GLEW_EXT_framebuffer_multisample || + !GLEW_ARB_texture_multisample || + /* Only needed for GPU_offscreen_read_pixels. + * We could add an arg if we intend to use multi-samle + * offscreen buffers w/o reading their pixels */ + !GLEW_EXT_framebuffer_blit || + /* This is required when blitting from a multi-sampled buffers, + * even though we're not scaling. */ + !GLEW_EXT_framebuffer_multisample_blit_scaled) + { + samples = 0; + } + } + + ofs->depth = GPU_texture_create_depth_multisample(width, height, samples, err_out); if (!ofs->depth) { GPU_offscreen_free(ofs); return NULL; @@ -1416,7 +1475,7 @@ GPUOffScreen *GPU_offscreen_create(int width, int height, char err_out[256]) return NULL; } - ofs->color = GPU_texture_create_2D(width, height, NULL, GPU_HDR_NONE, err_out); + ofs->color = GPU_texture_create_2D_multisample(width, height, NULL, GPU_HDR_NONE, samples, err_out); if (!ofs->color) { GPU_offscreen_free(ofs); return NULL; @@ -1470,17 +1529,96 @@ void GPU_offscreen_unbind(GPUOffScreen *ofs, bool restore) void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels) { - glReadPixels(0, 0, ofs->color->w, ofs->color->h, GL_RGBA, type, pixels); + const int w = ofs->color->w_orig; + const int h = ofs->color->h_orig; + + if (ofs->color->target == GL_TEXTURE_2D_MULTISAMPLE) { + /* For a multi-sample texture, + * we need to create an intermediate buffer to blit to, + * before its copied using 'glReadPixels' */ + + /* not needed since 'ofs' needs to be bound to the framebuffer already */ +// #define USE_FBO_CTX_SWITCH + + GLuint fbo_blit = 0; + GLuint tex_blit = 0; + GLenum status; + + /* create texture for new 'fbo_blit' */ + glGenTextures(1, &tex_blit); + if (!tex_blit) { + goto finally; + } + + glBindTexture(GL_TEXTURE_2D, tex_blit); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, type, 0); + +#ifdef USE_FBO_CTX_SWITCH + /* read from multi-sample buffer */ + glBindFramebufferEXT(GL_READ_FRAMEBUFFER, ofs->color->fb->object); + glFramebufferTexture2DEXT( + GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + ofs->color->fb_attachment, + GL_TEXTURE_2D_MULTISAMPLE, ofs->color->bindcode, 0); + status = glCheckFramebufferStatus(GL_READ_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + goto finally; + } +#endif + + /* write into new single-sample buffer */ + glGenFramebuffersEXT(1, &fbo_blit); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_blit); + glFramebufferTexture2DEXT( + GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, tex_blit, 0); + status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + goto finally; + } + + /* perform the copy */ + glBlitFramebufferEXT(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST); + + /* read the results */ + glBindFramebufferEXT(GL_READ_FRAMEBUFFER, fbo_blit); + glReadPixels(0, 0, w, h, GL_RGBA, type, pixels); + +#ifdef USE_FBO_CTX_SWITCH + /* restore the original frame-bufer */ + glBindFramebufferEXT(GL_FRAMEBUFFER, ofs->color->fb->object); +#undef USE_FBO_CTX_SWITCH +#endif + + +finally: + /* cleanup */ + if (tex_blit) { + glDeleteTextures(1, &tex_blit); + } + if (fbo_blit) { + glDeleteFramebuffersEXT(1, &fbo_blit); + } + + GPU_ASSERT_NO_GL_ERRORS("Read Multi-Sample Pixels"); + } + else { + glReadPixels(0, 0, w, h, GL_RGBA, type, pixels); + } } int GPU_offscreen_width(const GPUOffScreen *ofs) { - return ofs->color->w; + return ofs->color->w_orig; } int GPU_offscreen_height(const GPUOffScreen *ofs) { - return ofs->color->h; + return ofs->color->h_orig; +} + +int GPU_offscreen_color_texture(const GPUOffScreen *ofs) +{ + return ofs->color->bindcode; } /* GPUShader */ @@ -1533,7 +1671,7 @@ static const char *gpu_shader_version(bool use_opensubdiv) { #ifdef WITH_OPENSUBDIV if (use_opensubdiv) { - return "#version 150"; + return "#version 130\n"; } #else UNUSED_VARS(use_opensubdiv); @@ -1550,16 +1688,21 @@ static const char *gpu_shader_version(bool use_opensubdiv) } -static void gpu_shader_standard_extensions(char defines[MAX_EXT_DEFINE_LENGTH]) +static void gpu_shader_standard_extensions(char defines[MAX_EXT_DEFINE_LENGTH], bool use_opensubdiv) { #ifdef WITH_OPENSUBDIV - strcat(defines, "#extension GL_ARB_texture_query_lod: enable\n" - "#extension GL_ARB_gpu_shader5 : enable\n" - "#extension GL_ARB_explicit_attrib_location : require\n"); + if (use_opensubdiv) { + strcat(defines, "#extension GL_ARB_texture_query_lod: enable\n" + "#extension GL_ARB_gpu_shader5 : enable\n" + "#extension GL_ARB_explicit_attrib_location : require\n"); + } + else if (GPU_bicubic_bump_support()) + strcat(defines, "#extension GL_ARB_texture_query_lod: enable\n"); #else /* need this extension for high quality bump mapping */ if (GPU_bicubic_bump_support()) strcat(defines, "#extension GL_ARB_texture_query_lod: enable\n"); + (void) use_opensubdiv; #endif if (GPU_geometry_shader_support()) @@ -1674,16 +1817,42 @@ void GPU_program_parameter_4f(GPUProgram *program, unsigned int location, float glProgramLocalParameter4fARB(program->type, location, x, y, z, w); } - - -GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const char *geocode, const char *libcode, const char *defines, int input, int output, int number) +GPUShader *GPU_shader_create(const char *vertexcode, + const char *fragcode, + const char *geocode, + const char *libcode, + const char *defines, + int input, + int output, + int number) +{ + return GPU_shader_create_ex(vertexcode, + fragcode, + geocode, + libcode, + defines, + input, + output, + number, + GPU_SHADER_FLAGS_NONE); +} + +GPUShader *GPU_shader_create_ex(const char *vertexcode, + const char *fragcode, + const char *geocode, + const char *libcode, + const char *defines, + int input, + int output, + int number, + const int flags) { -#ifdef WITH_OPENSUBDIF +#ifdef WITH_OPENSUBDIV /* TODO(sergey): used to add #version 150 to the geometry shader. - * Could safely be renamed to "use_geometry_code" since it's evry much - * liely any of geometry code will want to use GLSL 1.5. + * Could safely be renamed to "use_geometry_code" since it's very + * likely any of geometry code will want to use GLSL 1.5. */ - bool use_opensubdiv = geocode != NULL; + bool use_opensubdiv = (flags & GPU_SHADER_FLAGS_SPECIAL_OPENSUBDIV) != 0; #else bool use_opensubdiv = false; #endif @@ -1694,6 +1863,10 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const char standard_defines[MAX_DEFINE_LENGTH] = ""; char standard_extensions[MAX_EXT_DEFINE_LENGTH] = ""; +#ifndef WITH_OPENSUBDIV + UNUSED_VARS(flags); +#endif + if (!GLEW_ARB_vertex_shader || !GLEW_ARB_fragment_shader || (geocode && !GPU_geometry_shader_support())) return NULL; @@ -1719,7 +1892,7 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const } gpu_shader_standard_defines(use_opensubdiv, standard_defines); - gpu_shader_standard_extensions(standard_extensions); + gpu_shader_standard_extensions(standard_extensions, use_opensubdiv); if (vertexcode) { const char *source[5]; @@ -1850,7 +2023,7 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const #ifdef WITH_OPENSUBDIV /* TODO(sergey): Find a better place for this. */ - { + if (use_opensubdiv && GLEW_VERSION_4_1) { glProgramUniform1i(shader->object, glGetUniformLocation(shader->object, "FVarDataBuffer"), 31); /* GL_TEXTURE31 */ @@ -1932,7 +2105,7 @@ int GPU_shader_get_uniform(GPUShader *shader, const char *name) void GPU_shader_uniform_vector(GPUShader *UNUSED(shader), int location, int length, int arraysize, const float *value) { - if (location == -1) + if (location == -1 || value == NULL) return; GPU_ASSERT_NO_GL_ERRORS("Pre Uniform Vector"); diff --git a/source/blender/gpu/intern/gpu_init_exit.c b/source/blender/gpu/intern/gpu_init_exit.c index 3a8a6fca23b..da4dd65d2e1 100644 --- a/source/blender/gpu/intern/gpu_init_exit.c +++ b/source/blender/gpu/intern/gpu_init_exit.c @@ -49,7 +49,7 @@ static bool initialized = false; void GPU_init(void) { - /* can't avoid calling this multiple times, see wm_window_add_ghostwindow */ + /* can't avoid calling this multiple times, see wm_window_ghostwindow_add */ if (initialized) return; diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index 5b647232934..82902f8d69c 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -141,6 +141,7 @@ struct GPULamp { float dynimat[4][4]; float spotsi, spotbl, k; + float spotvec[2]; float dyndist, dynatt1, dynatt2; float dist, att1, att2; float shadow_color[3]; @@ -536,12 +537,15 @@ static GPUNodeLink *lamp_get_visibility(GPUMaterial *mat, GPULamp *lamp, GPUNode if (lamp->type == LA_SPOT) { if (lamp->mode & LA_SQUARE) { - mat->dynproperty |= DYN_LAMP_VEC|DYN_LAMP_IMAT; - GPU_link(mat, "lamp_visibility_spot_square", GPU_dynamic_uniform(lamp->dynvec, GPU_DYNAMIC_LAMP_DYNVEC, lamp->ob), GPU_dynamic_uniform((float*)lamp->dynimat, GPU_DYNAMIC_LAMP_DYNIMAT, lamp->ob), *lv, &inpr); + mat->dynproperty |= DYN_LAMP_VEC | DYN_LAMP_IMAT; + GPU_link(mat, "lamp_visibility_spot_square", GPU_dynamic_uniform(lamp->dynvec, GPU_DYNAMIC_LAMP_DYNVEC, lamp->ob), GPU_dynamic_uniform((float*)lamp->dynimat, GPU_DYNAMIC_LAMP_DYNIMAT, lamp->ob), + GPU_dynamic_uniform((float *)lamp->spotvec, GPU_DYNAMIC_LAMP_SPOTSCALE, lamp->ob), *lv, &inpr); } else { - mat->dynproperty |= DYN_LAMP_VEC; - GPU_link(mat, "lamp_visibility_spot_circle", GPU_dynamic_uniform(lamp->dynvec, GPU_DYNAMIC_LAMP_DYNVEC, lamp->ob), *lv, &inpr); + mat->dynproperty |= DYN_LAMP_VEC | DYN_LAMP_IMAT; + GPU_link(mat, "lamp_visibility_spot_circle", GPU_dynamic_uniform(lamp->dynvec, GPU_DYNAMIC_LAMP_DYNVEC, lamp->ob), + GPU_dynamic_uniform((float *)lamp->dynimat, GPU_DYNAMIC_LAMP_DYNIMAT, lamp->ob), + GPU_dynamic_uniform((float *)lamp->spotvec, GPU_DYNAMIC_LAMP_SPOTSCALE, lamp->ob), *lv, &inpr); } GPU_link(mat, "lamp_visibility_spot", GPU_dynamic_uniform(&lamp->spotsi, GPU_DYNAMIC_LAMP_SPOTSIZE, lamp->ob), GPU_dynamic_uniform(&lamp->spotbl, GPU_DYNAMIC_LAMP_SPOTSIZE, lamp->ob), inpr, visifac, &visifac); @@ -1854,24 +1858,41 @@ static void gpu_lamp_calc_winmat(GPULamp *lamp) temp = 0.5f * lamp->size * cosf(angle) / sinf(angle); pixsize = lamp->d / temp; wsize = pixsize * 0.5f * lamp->size; - perspective_m4(lamp->winmat, -wsize, wsize, -wsize, wsize, lamp->d, lamp->clipend); + if (lamp->type & LA_SPOT) { + /* compute shadows according to X and Y scaling factors */ + perspective_m4( + lamp->winmat, + -wsize * lamp->spotvec[0], wsize * lamp->spotvec[0], + -wsize * lamp->spotvec[1], wsize * lamp->spotvec[1], + lamp->d, lamp->clipend); + } + else { + perspective_m4(lamp->winmat, -wsize, wsize, -wsize, wsize, lamp->d, lamp->clipend); + } } } void GPU_lamp_update(GPULamp *lamp, int lay, int hide, float obmat[4][4]) { float mat[4][4]; + float obmat_scale[3]; lamp->lay = lay; lamp->hide = hide; - copy_m4_m4(mat, obmat); - normalize_m4(mat); + normalize_m4_m4_ex(mat, obmat, obmat_scale); copy_v3_v3(lamp->vec, mat[2]); copy_v3_v3(lamp->co, mat[3]); copy_m4_m4(lamp->obmat, mat); invert_m4_m4(lamp->imat, mat); + + /* update spotlamp scale on X and Y axis */ + lamp->spotvec[0] = obmat_scale[0] / obmat_scale[2]; + lamp->spotvec[1] = obmat_scale[1] / obmat_scale[2]; + + /* makeshadowbuf */ + gpu_lamp_calc_winmat(lamp); } void GPU_lamp_update_colors(GPULamp *lamp, float r, float g, float b, float energy) @@ -1895,8 +1916,6 @@ void GPU_lamp_update_spot(GPULamp *lamp, float spotsize, float spotblend) { lamp->spotsi = cosf(spotsize * 0.5f); lamp->spotbl = (1.0f - lamp->spotsi) * spotblend; - - gpu_lamp_calc_winmat(lamp); } static void gpu_lamp_from_blender(Scene *scene, Object *ob, Object *par, Lamp *la, GPULamp *lamp) @@ -1941,9 +1960,6 @@ static void gpu_lamp_from_blender(Scene *scene, Object *ob, Object *par, Lamp *l /* arbitrary correction for the fact we do no soft transition */ lamp->bias *= 0.25f; - - /* makeshadowbuf */ - gpu_lamp_calc_winmat(lamp); } static void gpu_lamp_shadow_free(GPULamp *lamp) diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl index 54864b2b185..5b62739b0eb 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -149,6 +149,7 @@ void geom(vec3 co, vec3 nor, mat4 viewinvmat, vec3 attorco, vec2 attuv, vec4 att uv_attribute(attuv, uv); normal = -normalize(nor); /* blender render normal is negated */ vcol_attribute(attvcol, vcol); + srgb_to_linearrgb(vcol, vcol); vcol_alpha = attvcol.a; frontback = (gl_FrontFacing)? 1.0: 0.0; } @@ -1583,11 +1584,13 @@ void lamp_visibility_sphere(float lampdist, float dist, float visifac, out float outvisifac= visifac*max(t, 0.0)/lampdist; } -void lamp_visibility_spot_square(vec3 lampvec, mat4 lampimat, vec3 lv, out float inpr) +void lamp_visibility_spot_square(vec3 lampvec, mat4 lampimat, vec2 scale, vec3 lv, out float inpr) { if(dot(lv, lampvec) > 0.0) { vec3 lvrot = (lampimat*vec4(lv, 0.0)).xyz; - float x = max(abs(lvrot.x/lvrot.z), abs(lvrot.y/lvrot.z)); + /* without clever non-uniform scale, we could do: */ + // float x = max(abs(lvrot.x / lvrot.z), abs(lvrot.y / lvrot.z)); + float x = max(abs((lvrot.x / scale.x) / lvrot.z), abs((lvrot.y / scale.y) / lvrot.z)); inpr = 1.0/sqrt(1.0 + x*x); } @@ -1595,9 +1598,21 @@ void lamp_visibility_spot_square(vec3 lampvec, mat4 lampimat, vec3 lv, out float inpr = 0.0; } -void lamp_visibility_spot_circle(vec3 lampvec, vec3 lv, out float inpr) +void lamp_visibility_spot_circle(vec3 lampvec, mat4 lampimat, vec2 scale, vec3 lv, out float inpr) { - inpr = dot(lv, lampvec); + /* without clever non-uniform scale, we could do: */ + // inpr = dot(lv, lampvec); + if (dot(lv, lampvec) > 0.0) { + vec3 lvrot = (lampimat * vec4(lv, 0.0)).xyz; + float x = abs(lvrot.x / lvrot.z); + float y = abs(lvrot.y / lvrot.z); + + float ellipse = abs((x * x) / (scale.x * scale.x) + (y * y) / (scale.y * scale.y)); + + inpr = 1.0 / sqrt(1.0 + ellipse); + } + else + inpr = 0.0; } void lamp_visibility_spot(float spotsi, float spotbl, float inpr, float visifac, out float outvisifac) |