diff options
author | Dalai Felinto <dfelinto@gmail.com> | 2017-04-28 20:25:57 +0300 |
---|---|---|
committer | Dalai Felinto <dfelinto@gmail.com> | 2017-04-28 20:25:57 +0300 |
commit | b868f43fd382c0497b82f29685f6280d9692a0fb (patch) | |
tree | 7fac681bd1e08283cd3168a30b5362f250bf6da2 | |
parent | ba4f47ce8eb00284da7d6b17bf9c3f02506617e3 (diff) |
Cycles support for preview on viewport with core profile
This upgrade the drawing code to use latest opengl calls.
Also, it adds a fallback shader for opencolorio.
Reviewers: sergey, brecht
Subscribers: merwin, fclem
Differential Revision: https://developer.blender.org/D2652
-rw-r--r-- | intern/cycles/device/device.cpp | 321 | ||||
-rw-r--r-- | intern/cycles/device/device.h | 22 | ||||
-rw-r--r-- | intern/cycles/device/device_cuda.cpp | 57 | ||||
-rw-r--r-- | intern/cycles/device/device_multi.cpp | 9 | ||||
-rw-r--r-- | intern/cycles/render/buffers.cpp | 6 |
5 files changed, 302 insertions, 113 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) diff --git a/intern/cycles/device/device.h b/intern/cycles/device/device.h index 6051dd8b3eb..21d29a801ae 100644 --- a/intern/cycles/device/device.h +++ b/intern/cycles/device/device.h @@ -229,13 +229,26 @@ struct DeviceDrawParams { class Device { protected: - Device(DeviceInfo& info_, Stats &stats_, bool background) : background(background), vertex_buffer(0), info(info_), stats(stats_) {} + enum { + FALLBACK_SHADER_STATUS_NONE = 0, + FALLBACK_SHADER_STATUS_ERROR, + FALLBACK_SHADER_STATUS_SUCCESS, + }; + + Device(DeviceInfo& info_, Stats &stats_, bool background) : background(background), + vertex_buffer(0), + fallback_status(FALLBACK_SHADER_STATUS_NONE), fallback_shader_program(0), + info(info_), stats(stats_) {} bool background; string error_msg; /* used for real time display */ unsigned int vertex_buffer; + int fallback_status, fallback_shader_program; + int image_texture_location, fullscreen_location; + + bool bind_fallback_display_space_shader(const float width, const float height); public: virtual ~Device(); @@ -300,9 +313,10 @@ public: virtual void task_cancel() = 0; /* opengl drawing */ - virtual void draw_pixels(device_memory& mem, int y, int w, int h, - int dx, int dy, int width, int height, bool transparent, - const DeviceDrawParams &draw_params); + virtual void draw_pixels(device_memory& mem, int y, + int w, int h, int width, int height, + int dx, int dy, int dw, int dh, + bool transparent, const DeviceDrawParams &draw_params); #ifdef WITH_NETWORK /* networking */ diff --git a/intern/cycles/device/device_cuda.cpp b/intern/cycles/device/device_cuda.cpp index ef283c9d455..3532e640eaa 100644 --- a/intern/cycles/device/device_cuda.cpp +++ b/intern/cycles/device/device_cuda.cpp @@ -1194,10 +1194,14 @@ public: } } - void draw_pixels(device_memory& mem, int y, int w, int h, int dx, int dy, int width, int height, bool transparent, + void draw_pixels( + device_memory& mem, int y, + int w, int h, int width, int height, + int dx, int dy, int dw, int dh, bool transparent, const DeviceDrawParams &draw_params) { if(!background) { + const bool use_fallback_shader = (draw_params.bind_display_space_shader_cb == NULL); PixelMem pmem = pixel_mem_map[mem.device_pointer]; float *vpointer; @@ -1214,10 +1218,12 @@ public: glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pmem.cuPBO); glBindTexture(GL_TEXTURE_2D, pmem.cuTexId); - if(mem.data_type == TYPE_HALF) + if(mem.data_type == TYPE_HALF) { glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_HALF_FLOAT, (void*)offset); - else + } + else { glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, (void*)offset); + } glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); glEnable(GL_TEXTURE_2D); @@ -1227,14 +1233,21 @@ public: glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } - glColor3f(1.0f, 1.0f, 1.0f); - - if(draw_params.bind_display_space_shader_cb) { + GLint shader_program; + if(use_fallback_shader) { + if(!bind_fallback_display_space_shader(dw, dh)) { + return; + } + shader_program = fallback_shader_program; + } + else { draw_params.bind_display_space_shader_cb(); + glGetIntegerv(GL_CURRENT_PROGRAM, &shader_program); } - if(!vertex_buffer) + 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 */ @@ -1267,25 +1280,33 @@ public: glUnmapBuffer(GL_ARRAY_BUFFER); } - glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), 0); - glVertexPointer(2, GL_FLOAT, 4 * sizeof(float), (char *)NULL + 2 * sizeof(float)); + GLuint vertex_array_object; + GLuint position_attribute, texcoord_attribute; - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glGenVertexArrays(1, &vertex_array_object); + glBindVertexArray(vertex_array_object); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + texcoord_attribute = glGetAttribLocation(shader_program, "texCoord"); + position_attribute = glGetAttribLocation(shader_program, "pos"); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); + glEnableVertexAttribArray(texcoord_attribute); + glEnableVertexAttribArray(position_attribute); - glBindBuffer(GL_ARRAY_BUFFER, 0); + 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(draw_params.unbind_display_space_shader_cb) { + if(use_fallback_shader) { + glUseProgram(0); + } + else { draw_params.unbind_display_space_shader_cb(); } - if(transparent) + if(transparent) { glDisable(GL_BLEND); + } glBindTexture(GL_TEXTURE_2D, 0); glDisable(GL_TEXTURE_2D); @@ -1295,7 +1316,7 @@ public: return; } - Device::draw_pixels(mem, y, w, h, dx, dy, width, height, transparent, draw_params); + Device::draw_pixels(mem, y, w, h, width, height, dx, dy, dw, dh, transparent, draw_params); } void thread_run(DeviceTask *task) diff --git a/intern/cycles/device/device_multi.cpp b/intern/cycles/device/device_multi.cpp index 624260a81c8..8616e31d3b9 100644 --- a/intern/cycles/device/device_multi.cpp +++ b/intern/cycles/device/device_multi.cpp @@ -254,8 +254,11 @@ public: mem.device_pointer = tmp; } - void 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) + void 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) { device_ptr tmp = rgba.device_pointer; int i = 0, sub_h = h/devices.size(); @@ -269,7 +272,7 @@ public: /* adjust math for w/width */ rgba.device_pointer = sub.ptr_map[tmp]; - sub.device->draw_pixels(rgba, sy, w, sh, dx, sdy, width, sheight, transparent, draw_params); + sub.device->draw_pixels(rgba, sy, w, sh, width, sheight, dx, sdy, dw, dh, transparent, draw_params); i++; } diff --git a/intern/cycles/render/buffers.cpp b/intern/cycles/render/buffers.cpp index fe2c2e78926..49934143ee9 100644 --- a/intern/cycles/render/buffers.cpp +++ b/intern/cycles/render/buffers.cpp @@ -371,7 +371,11 @@ void DisplayBuffer::draw(Device *device, const DeviceDrawParams& draw_params) if(draw_width != 0 && draw_height != 0) { device_memory& rgba = rgba_data(); - device->draw_pixels(rgba, 0, draw_width, draw_height, params.full_x, params.full_y, params.width, params.height, transparent, draw_params); + device->draw_pixels( + rgba, 0, + draw_width, draw_height, params.width, params.height, + params.full_x, params.full_y, params.full_width, params.full_height, + transparent, draw_params); } } |