diff options
Diffstat (limited to 'intern/cycles/device/device.cpp')
-rw-r--r-- | intern/cycles/device/device.cpp | 321 |
1 files changed, 234 insertions, 87 deletions
diff --git a/intern/cycles/device/device.cpp b/intern/cycles/device/device.cpp index c024021b4b3..4c4e862ed1f 100644 --- a/intern/cycles/device/device.cpp +++ b/intern/cycles/device/device.cpp @@ -23,6 +23,7 @@ #include "util/util_debug.h" #include "util/util_foreach.h" #include "util/util_half.h" +#include "util/util_logging.h" #include "util/util_math.h" #include "util/util_opengl.h" #include "util/util_time.h" @@ -75,8 +76,13 @@ std::ostream& operator <<(std::ostream &os, Device::~Device() { - if(!background && vertex_buffer != 0) { - glDeleteBuffers(1, &vertex_buffer); + if(!background) { + if(vertex_buffer != 0) { + glDeleteBuffers(1, &vertex_buffer); + } + if(fallback_shader_program != 0) { + glDeleteProgram(fallback_shader_program); + } } } @@ -98,125 +104,266 @@ void Device::pixels_free(device_memory& mem) mem_free(mem); } -void Device::draw_pixels(device_memory& rgba, int y, int w, int h, int dx, int dy, int width, int height, bool transparent, - const DeviceDrawParams &draw_params) +/* TODO move shaders to standalone .glsl file. */ +const char *FALLBACK_VERTEX_SHADER = +"#version 330\n" +"uniform vec2 fullscreen;\n" +"in vec2 texCoord;\n" +"in vec2 pos;\n" +"out vec2 texCoord_interp;\n" +"\n" +"vec2 normalize_coordinates()\n" +"{\n" +" return (vec2(2.0) * (pos / fullscreen)) - vec2(1.0);\n" +"}\n" +"\n" +"void main()\n" +"{\n" +" gl_Position = vec4(normalize_coordinates(), 0.0, 1.0);\n" +" texCoord_interp = texCoord;\n" +"}\n\0"; + +const char *FALLBACK_FRAGMENT_SHADER = +"#version 330\n" +"uniform sampler2D image_texture;\n" +"in vec2 texCoord_interp;\n" +"out vec4 fragColor;\n" +"\n" +"void main()\n" +"{\n" +" fragColor = texture(image_texture, texCoord_interp);\n" +"}\n\0"; + +static void shader_print_errors(const char *task, const char *log, const char *code) { - pixels_copy_from(rgba, y, w, h); + LOG(ERROR) << "Shader: " << task << " error:"; + LOG(ERROR) << "===== shader string ===="; - if(transparent) { - glEnable(GL_BLEND); - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + stringstream stream(code); + string partial; + + int line = 1; + while(getline(stream, partial, '\n')) { + if(line < 10) { + LOG(ERROR) << " " << line << " " << partial; + } + else { + LOG(ERROR) << line << " " << partial; + } + line++; } + LOG(ERROR) << log; +} - glColor3f(1.0f, 1.0f, 1.0f); +static int bind_fallback_shader(void) +{ + GLint status; + GLchar log[5000]; + GLsizei length = 0; + GLuint program = 0; - if(rgba.data_type == TYPE_HALF) { - /* for multi devices, this assumes the inefficient method that we allocate - * all pixels on the device even though we only render to a subset */ - GLhalf *data_pointer = (GLhalf*)rgba.data_pointer; - float vbuffer[16], *basep; - float *vp = NULL; + struct Shader { + const char *source; + GLenum type; + } shaders[2] = { + {FALLBACK_VERTEX_SHADER, GL_VERTEX_SHADER}, + {FALLBACK_FRAGMENT_SHADER, GL_FRAGMENT_SHADER} + }; - data_pointer += 4*y*w; + program = glCreateProgram(); - /* draw half float texture, GLSL shader for display transform assumed to be bound */ - GLuint texid; - glGenTextures(1, &texid); - glBindTexture(GL_TEXTURE_2D, texid); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, w, h, 0, GL_RGBA, GL_HALF_FLOAT, data_pointer); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + for(int i = 0; i < 2; i++) { + GLuint shader = glCreateShader(shaders[i].type); + + string source_str = shaders[i].source; + const char *c_str = source_str.c_str(); - glEnable(GL_TEXTURE_2D); + glShaderSource(shader, 1, &c_str, NULL); + glCompileShader(shader); - if(draw_params.bind_display_space_shader_cb) { - draw_params.bind_display_space_shader_cb(); + glGetShaderiv(shader, GL_COMPILE_STATUS, &status); + + if(!status) { + glGetShaderInfoLog(shader, sizeof(log), &length, log); + shader_print_errors("compile", log, c_str); + return 0; } - if(GLEW_VERSION_1_5) { - if(!vertex_buffer) - glGenBuffers(1, &vertex_buffer); + glAttachShader(program, shader); + } + + /* Link output. */ + glBindFragDataLocation(program, 0, "fragColor"); - glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); - /* invalidate old contents - avoids stalling if buffer is still waiting in queue to be rendered */ - glBufferData(GL_ARRAY_BUFFER, 16 * sizeof(float), NULL, GL_STREAM_DRAW); + /* Link and error check. */ + glLinkProgram(program); - vp = (float *)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); + glGetProgramiv(program, GL_LINK_STATUS, &status); + if(!status) { + glGetShaderInfoLog(program, sizeof(log), &length, log); + shader_print_errors("linking", log, FALLBACK_VERTEX_SHADER); + shader_print_errors("linking", log, FALLBACK_FRAGMENT_SHADER); + return 0; + } - basep = NULL; + return program; +} + +bool Device::bind_fallback_display_space_shader(const float width, const float height) +{ + if(fallback_status == FALLBACK_SHADER_STATUS_ERROR) { + return false; + } + + if(fallback_status == FALLBACK_SHADER_STATUS_NONE) { + fallback_shader_program = bind_fallback_shader(); + fallback_status = FALLBACK_SHADER_STATUS_ERROR; + + if (fallback_shader_program == 0) { + return false; } - else { - basep = vbuffer; - vp = vbuffer; + + glUseProgram(fallback_shader_program); + image_texture_location = glGetUniformLocation(fallback_shader_program, "image_texture"); + if(image_texture_location < 0) { + LOG(ERROR) << "Shader doesn't containt the 'image_texture' uniform."; + return false; } - if(vp) { - /* texture coordinate - vertex pair */ - vp[0] = 0.0f; - vp[1] = 0.0f; - vp[2] = dx; - vp[3] = dy; - - vp[4] = 1.0f; - vp[5] = 0.0f; - vp[6] = (float)width + dx; - vp[7] = dy; - - vp[8] = 1.0f; - vp[9] = 1.0f; - vp[10] = (float)width + dx; - vp[11] = (float)height + dy; - - vp[12] = 0.0f; - vp[13] = 1.0f; - vp[14] = dx; - vp[15] = (float)height + dy; - - if(vertex_buffer) - glUnmapBuffer(GL_ARRAY_BUFFER); + fullscreen_location = glGetUniformLocation(fallback_shader_program, "fullscreen"); + if(fullscreen_location < 0) { + LOG(ERROR) << "Shader doesn't containt the 'fullscreen' uniform."; + return false; } - glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), basep); - glVertexPointer(2, GL_FLOAT, 4 * sizeof(float), ((char *)basep) + 2 * sizeof(float)); + fallback_status = FALLBACK_SHADER_STATUS_SUCCESS; + } - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); + /* Run this every time. */ + glUseProgram(fallback_shader_program); + glUniform1i(image_texture_location, 0); + glUniform2f(fullscreen_location, width, height); + return true; +} - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); +void Device::draw_pixels( + device_memory& rgba, int y, + int w, int h, int width, int height, + int dx, int dy, int dw, int dh, + bool transparent, const DeviceDrawParams &draw_params) +{ + const bool use_fallback_shader = (draw_params.bind_display_space_shader_cb == NULL); + pixels_copy_from(rgba, y, w, h); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); + GLuint texid; + glGenTextures(1, &texid); + glBindTexture(GL_TEXTURE_2D, texid); - if(vertex_buffer) { - glBindBuffer(GL_ARRAY_BUFFER, 0); - } + if(rgba.data_type == TYPE_HALF) { + GLhalf *data_pointer = (GLhalf*)rgba.data_pointer; + data_pointer += 4 * y * w; + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, w, h, 0, GL_RGBA, GL_HALF_FLOAT, data_pointer); + } + else { + uint8_t *data_pointer = (uint8_t*)rgba.data_pointer; + data_pointer += 4 * y * w; + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data_pointer); + } - if(draw_params.unbind_display_space_shader_cb) { - draw_params.unbind_display_space_shader_cb(); - } + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + glEnable(GL_TEXTURE_2D); + + if(transparent) { + glEnable(GL_BLEND); + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + } - glBindTexture(GL_TEXTURE_2D, 0); - glDisable(GL_TEXTURE_2D); - glDeleteTextures(1, &texid); + GLint shader_program; + if(use_fallback_shader) { + if (!bind_fallback_display_space_shader(dw, dh)) { + return; + } + shader_program = fallback_shader_program; } else { - /* fallback for old graphics cards that don't support GLSL, half float, - * and non-power-of-two textures */ - glPixelZoom((float)width/(float)w, (float)height/(float)h); - glRasterPos2f(dx, dy); + draw_params.bind_display_space_shader_cb(); + glGetIntegerv(GL_CURRENT_PROGRAM, &shader_program); + } + + if(!vertex_buffer) { + glGenBuffers(1, &vertex_buffer); + } + + glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); + /* invalidate old contents - avoids stalling if buffer is still waiting in queue to be rendered */ + glBufferData(GL_ARRAY_BUFFER, 16 * sizeof(float), NULL, GL_STREAM_DRAW); + + float *vpointer = (float *)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); + + if(vpointer) { + /* texture coordinate - vertex pair */ + vpointer[0] = 0.0f; + vpointer[1] = 0.0f; + vpointer[2] = dx; + vpointer[3] = dy; - uint8_t *pixels = (uint8_t*)rgba.data_pointer; + vpointer[4] = 1.0f; + vpointer[5] = 0.0f; + vpointer[6] = (float)width + dx; + vpointer[7] = dy; - pixels += 4*y*w; + vpointer[8] = 1.0f; + vpointer[9] = 1.0f; + vpointer[10] = (float)width + dx; + vpointer[11] = (float)height + dy; - glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + vpointer[12] = 0.0f; + vpointer[13] = 1.0f; + vpointer[14] = dx; + vpointer[15] = (float)height + dy; - glRasterPos2f(0.0f, 0.0f); - glPixelZoom(1.0f, 1.0f); + if(vertex_buffer) { + glUnmapBuffer(GL_ARRAY_BUFFER); + } } - if(transparent) + GLuint vertex_array_object; + GLuint position_attribute, texcoord_attribute; + + glGenVertexArrays(1, &vertex_array_object); + glBindVertexArray(vertex_array_object); + + texcoord_attribute = glGetAttribLocation(shader_program, "texCoord"); + position_attribute = glGetAttribLocation(shader_program, "pos"); + + glEnableVertexAttribArray(texcoord_attribute); + glEnableVertexAttribArray(position_attribute); + + glVertexAttribPointer(texcoord_attribute, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (const GLvoid *)0); + glVertexAttribPointer(position_attribute, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (const GLvoid *)(sizeof(float) * 2)); + + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + if(vertex_buffer) { + glBindBuffer(GL_ARRAY_BUFFER, 0); + } + + if(use_fallback_shader) { + glUseProgram(0); + } + else { + draw_params.unbind_display_space_shader_cb(); + } + + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); + glDeleteTextures(1, &texid); + + if(transparent) { glDisable(GL_BLEND); + } } Device *Device::create(DeviceInfo& info, Stats &stats, bool background) |