Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'intern/cycles/device/device.cpp')
-rw-r--r--intern/cycles/device/device.cpp321
1 files changed, 234 insertions, 87 deletions
diff --git a/intern/cycles/device/device.cpp b/intern/cycles/device/device.cpp
index f64436aec7b..5ae83b56fcd 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"
@@ -77,8 +78,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);
+ }
}
}
@@ -100,125 +106,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)