Merge branch 'master' into blender2.8
authorSergey Sharybin <sergey.vfx@gmail.com>
Wed, 31 Oct 2018 10:49:04 +0000 (11:49 +0100)
committerSergey Sharybin <sergey.vfx@gmail.com>
Wed, 31 Oct 2018 10:49:04 +0000 (11:49 +0100)
1  2 
intern/cycles/device/device.cpp
intern/cycles/device/device.h
intern/cycles/device/device_cuda.cpp
intern/cycles/device/device_multi.cpp

index 906c01c619dd738d706e769bf6f54f87e9120406,7e20bb449c3be384bff52637aa0812f558a3af15..428cd4158bc1430f5c94ad2ceafe8ff49501bd0e
@@@ -78,275 -78,132 +78,275 @@@ std::ostream& operator <<(std::ostream 
  
  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);
 +              }
        }
  }
  
 -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)
  {
 -      assert(rgba.type == MEM_PIXELS);
 +      LOG(ERROR) << "Shader: " << task << " error:";
 +      LOG(ERROR) << "===== shader string ====";
  
 -      mem_copy_from(rgba, y, w, h, rgba.memory_elements_size(1));
 +      stringstream stream(code);
 +      string partial;
  
 -      if(transparent) {
 -              glEnable(GL_BLEND);
 -              glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
 +      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 *host_pointer = (GLhalf*)rgba.host_pointer;
 -              float vbuffer[16], *basep;
 -              float *vp = NULL;
 -
 -              host_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, host_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();
 +      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;
                }
  
 -              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);
 +
 +      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;
 +      }
  
 -                      vp = (float *)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
 +      if(fallback_status == FALLBACK_SHADER_STATUS_NONE) {
 +              fallback_shader_program = bind_fallback_shader();
 +              fallback_status = FALLBACK_SHADER_STATUS_ERROR;
  
 -                      basep = NULL;
 +              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);
  
 -              glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 -              glDisableClientState(GL_VERTEX_ARRAY);
 +      assert(rgba.type == MEM_PIXELS);
 +      mem_copy_from(rgba, y, w, h, rgba.memory_elements_size(1));
  
 -              if(vertex_buffer) {
 -                      glBindBuffer(GL_ARRAY_BUFFER, 0);
 -              }
 +      GLuint texid;
 +      glGenTextures(1, &texid);
 +      glBindTexture(GL_TEXTURE_2D, texid);
  
 -              if(draw_params.unbind_display_space_shader_cb) {
 -                      draw_params.unbind_display_space_shader_cb();
 -              }
 +      if(rgba.data_type == TYPE_HALF) {
 +              GLhalf *data_pointer = (GLhalf*)rgba.host_pointer;
 +              data_pointer += 4 * y * w;
 +              glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, w, h, 0, GL_RGBA, GL_HALF_FLOAT, data_pointer);
 +      }
 +      else {
 +              uint8_t *data_pointer = (uint8_t*)rgba.host_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);
 +
 +      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);
  
 -              uint8_t *pixels = (uint8_t*)rgba.host_pointer;
 +      if(vpointer) {
 +              /* texture coordinate - vertex pair */
 +              vpointer[0] = 0.0f;
 +              vpointer[1] = 0.0f;
 +              vpointer[2] = dx;
 +              vpointer[3] = dy;
  
 -              pixels += 4*y*w;
 +              vpointer[4] = 1.0f;
 +              vpointer[5] = 0.0f;
 +              vpointer[6] = (float)width + dx;
 +              vpointer[7] = dy;
  
 -              glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
 +              vpointer[8] = 1.0f;
 +              vpointer[9] = 1.0f;
 +              vpointer[10] = (float)width + dx;
 +              vpointer[11] = (float)height + dy;
  
 -              glRasterPos2f(0.0f, 0.0f);
 -              glPixelZoom(1.0f, 1.0f);
 +              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(transparent)
 +      if(use_fallback_shader) {
 +              glUseProgram(0);
 +      }
 +      else {
 +              draw_params.unbind_display_space_shader_cb();
 +      }
 +
 +      glBindTexture(GL_TEXTURE_2D, 0);
 +      glDeleteTextures(1, &texid);
 +
 +      if(transparent) {
                glDisable(GL_BLEND);
 +      }
  }
  
  Device *Device::create(DeviceInfo& info, Stats &stats, bool background)
@@@ -504,7 -361,6 +504,6 @@@ DeviceInfo Device::get_multi_device(con
  
        info.has_half_images = true;
        info.has_volume_decoupled = true;
-       info.bvh_layout_mask = BVH_LAYOUT_ALL;
        info.has_osl = true;
  
        foreach(const DeviceInfo &device, subdevices) {
                /* Accumulate device info. */
                info.has_half_images &= device.has_half_images;
                info.has_volume_decoupled &= device.has_volume_decoupled;
-               info.bvh_layout_mask = device.bvh_layout_mask & info.bvh_layout_mask;
                info.has_osl &= device.has_osl;
        }
  
index 585d98022791c7f299b9d36835ca729946d386fa,54a3ae1fe9f7d4b2bd3b1cdc98dec8931ca7587e..b09843e9f1278610a343050b1608e362ef8d7658
@@@ -58,7 -58,6 +58,6 @@@ public
        bool advanced_shading;          /* Supports full shading system. */
        bool has_half_images;           /* Support half-float textures. */
        bool has_volume_decoupled;      /* Decoupled volume shading. */
-       BVHLayoutMask bvh_layout_mask;  /* Bitmask of supported BVH layouts. */
        bool has_osl;                   /* Support Open Shading Language. */
        bool use_split_kernel;          /* Use split or mega kernel. */
        int cpu_threads;
@@@ -74,7 -73,6 +73,6 @@@
                advanced_shading = true;
                has_half_images = false;
                has_volume_decoupled = false;
-               bvh_layout_mask = BVH_LAYOUT_NONE;
                has_osl = false;
                use_split_kernel = false;
        }
@@@ -249,26 -247,13 +247,26 @@@ struct DeviceDrawParams 
  class Device {
        friend class device_sub_ptr;
  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);
  
        virtual device_ptr mem_alloc_sub_ptr(device_memory& /*mem*/, int /*offset*/, int /*size*/)
        {
@@@ -294,6 -279,7 +292,7 @@@ public
                fflush(stderr);
        }
        virtual bool show_samples() const { return false; }
+       virtual BVHLayoutMask get_bvh_layout_mask() const = 0;
  
        /* statistics */
        Stats &stats;
        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 */
index 22b1bc493c848b67c4aa67773342cc99bdf1edd3,f0e58f22ad40733c844241fd118cd91073a44844..1c2d35061cc5edf4cd2565293782e6021d83f7fc
@@@ -181,6 -181,10 +181,10 @@@ public
                return true;
        }
  
+       virtual BVHLayoutMask get_bvh_layout_mask() const {
+               return BVH_LAYOUT_BVH2;
+       }
  /*#ifdef NDEBUG
  #define cuda_abort()
  #else
                glGenTextures(1, &pmem.cuTexId);
                glBindTexture(GL_TEXTURE_2D, pmem.cuTexId);
                if(mem.data_type == TYPE_HALF)
 -                      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, pmem.w, pmem.h, 0, GL_RGBA, GL_HALF_FLOAT, NULL);
 +                      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, pmem.w, pmem.h, 0, GL_RGBA, GL_HALF_FLOAT, NULL);
                else
                        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, pmem.w, pmem.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
                }
        }
  
 -      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)
        {
                assert(mem.type == MEM_PIXELS);
  
                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;
  
  
                        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);
 -
                        if(transparent) {
                                glEnable(GL_BLEND);
                                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 */
                                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);
  
                        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)
@@@ -2477,7 -2463,6 +2481,6 @@@ void device_cuda_info(vector<DeviceInfo
                info.advanced_shading = (major >= 3);
                info.has_half_images = (major >= 3);
                info.has_volume_decoupled = false;
-               info.bvh_layout_mask = BVH_LAYOUT_BVH2;
  
                int pci_location[3] = {0, 0, 0};
                cuDeviceGetAttribute(&pci_location[0], CU_DEVICE_ATTRIBUTE_PCI_DOMAIN_ID, num);
index 587840e551fb0a52a126d53ba3dc2ca37ec3b16a,490ee3951c9f6506537b12e6313bdf418690133b..67f0f88028737b26988b66b836abc6307388f4ea
@@@ -103,6 -103,14 +103,14 @@@ public
                return devices.front().device->show_samples();
        }
  
+       virtual BVHLayoutMask get_bvh_layout_mask() const {
+               BVHLayoutMask bvh_layout_mask = BVH_LAYOUT_ALL;
+               foreach(const SubDevice& sub_device, devices) {
+                       bvh_layout_mask &= sub_device.device->get_bvh_layout_mask();
+               }
+               return bvh_layout_mask;
+       }
        bool load_kernels(const DeviceRequestedFeatures& requested_features)
        {
                foreach(SubDevice& sub, devices)
                        sub.device->const_copy_to(name, host, size);
        }
  
 -      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 key = rgba.device_pointer;
                int i = 0, sub_h = h/devices.size();
                        /* adjust math for w/width */
  
                        rgba.device_pointer = sub.ptr_map[key];
 -                      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++;
                }