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
This commit is contained in:
Dalai Felinto 2017-04-28 19:25:57 +02:00
parent ba4f47ce8e
commit b868f43fd3
5 changed files with 323 additions and 134 deletions

@ -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)
{
LOG(ERROR) << "Shader: " << task << " error:";
LOG(ERROR) << "===== shader string ====";
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;
}
static int bind_fallback_shader(void)
{
GLint status;
GLchar log[5000];
GLsizei length = 0;
GLuint program = 0;
struct Shader {
const char *source;
GLenum type;
} shaders[2] = {
{FALLBACK_VERTEX_SHADER, GL_VERTEX_SHADER},
{FALLBACK_FRAGMENT_SHADER, GL_FRAGMENT_SHADER}
};
program = glCreateProgram();
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();
glShaderSource(shader, 1, &c_str, NULL);
glCompileShader(shader);
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if(!status) {
glGetShaderInfoLog(shader, sizeof(log), &length, log);
shader_print_errors("compile", log, c_str);
return 0;
}
glAttachShader(program, shader);
}
/* Link output. */
glBindFragDataLocation(program, 0, "fragColor");
/* Link and error check. */
glLinkProgram(program);
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;
}
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;
}
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;
}
fullscreen_location = glGetUniformLocation(fallback_shader_program, "fullscreen");
if(fullscreen_location < 0) {
LOG(ERROR) << "Shader doesn't containt the 'fullscreen' uniform.";
return false;
}
fallback_status = FALLBACK_SHADER_STATUS_SUCCESS;
}
/* Run this every time. */
glUseProgram(fallback_shader_program);
glUniform1i(image_texture_location, 0);
glUniform2f(fullscreen_location, width, height);
return true;
}
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);
GLuint texid;
glGenTextures(1, &texid);
glBindTexture(GL_TEXTURE_2D, texid);
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);
}
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);
}
glColor3f(1.0f, 1.0f, 1.0f);
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;
data_pointer += 4*y*w;
/* 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);
glEnable(GL_TEXTURE_2D);
if(draw_params.bind_display_space_shader_cb) {
draw_params.bind_display_space_shader_cb();
GLint shader_program;
if(use_fallback_shader) {
if (!bind_fallback_display_space_shader(dw, dh)) {
return;
}
if(GLEW_VERSION_1_5) {
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);
vp = (float *)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
basep = NULL;
}
else {
basep = vbuffer;
vp = vbuffer;
}
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);
}
glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), basep);
glVertexPointer(2, GL_FLOAT, 4 * sizeof(float), ((char *)basep) + 2 * sizeof(float));
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
if(vertex_buffer) {
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
if(draw_params.unbind_display_space_shader_cb) {
draw_params.unbind_display_space_shader_cb();
}
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);
glDeleteTextures(1, &texid);
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);
uint8_t *pixels = (uint8_t*)rgba.data_pointer;
pixels += 4*y*w;
glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
glRasterPos2f(0.0f, 0.0f);
glPixelZoom(1.0f, 1.0f);
draw_params.bind_display_space_shader_cb();
glGetIntegerv(GL_CURRENT_PROGRAM, &shader_program);
}
if(transparent)
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;
vpointer[4] = 1.0f;
vpointer[5] = 0.0f;
vpointer[6] = (float)width + dx;
vpointer[7] = dy;
vpointer[8] = 1.0f;
vpointer[9] = 1.0f;
vpointer[10] = (float)width + dx;
vpointer[11] = (float)height + dy;
vpointer[12] = 0.0f;
vpointer[13] = 1.0f;
vpointer[14] = dx;
vpointer[15] = (float)height + dy;
if(vertex_buffer) {
glUnmapBuffer(GL_ARRAY_BUFFER);
}
}
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)

@ -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 */

@ -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);
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);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, 0);
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)

@ -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++;
}

@ -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);
}
}