From d6758db8710e7dd0afec6fd93e8490729c5d7dec Mon Sep 17 00:00:00 2001 From: Julian Waller Date: Sun, 15 Apr 2018 19:52:11 +0100 Subject: [PATCH] feat(opengl): #937 Switch OpenGL code to use a Core 4.5 profile --- .gitignore | 3 + src/accelerator/ogl/image/image_kernel.cpp | 49 +++++++++------ src/accelerator/ogl/image/image_shader.cpp | 62 ++++++++++++------- src/accelerator/ogl/util/device.cpp | 13 ++-- src/accelerator/ogl/util/shader.cpp | 28 ++++++--- src/accelerator/ogl/util/shader.h | 2 + src/core/frame/geometry.cpp | 13 ++-- src/core/frame/geometry.h | 3 +- .../screen/consumer/screen_consumer.cpp | 39 ++++++------ 9 files changed, 125 insertions(+), 87 deletions(-) diff --git a/.gitignore b/.gitignore index c7c2257877..3d0686ae39 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,6 @@ build CMakeFiles casparcg_server + +src/cmake-build-* +src/.idea diff --git a/src/accelerator/ogl/image/image_kernel.cpp b/src/accelerator/ogl/image/image_kernel.cpp index 4b4a0ca043..424f4e8878 100644 --- a/src/accelerator/ogl/image/image_kernel.cpp +++ b/src/accelerator/ogl/image/image_kernel.cpp @@ -310,10 +310,10 @@ struct image_kernel::impl double h = static_cast(params.background->height()); GL(glEnable(GL_SCISSOR_TEST)); - glScissor(static_cast(m_p[0] * w), + GL(glScissor(static_cast(m_p[0] * w), static_cast(m_p[1] * h), std::max(0, static_cast(m_s[0] * w)), - std::max(0, static_cast(m_s[1] * h))); + std::max(0, static_cast(m_s[1] * h)))); } // Set render target @@ -364,17 +364,18 @@ struct image_kernel::impl // Draw switch (params.geometry.type()) { - case core::frame_geometry::geometry_type::quad: - case core::frame_geometry::geometry_type::quad_list: { - glClientActiveTexture(GL_TEXTURE0); + case core::frame_geometry::geometry_type::triangles: { - glDisableClientState(GL_EDGE_FLAG_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - glDisableClientState(GL_INDEX_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); + GLuint vao; + GLuint vbo; - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glEnableClientState(GL_VERTEX_ARRAY); + GL(glGenVertexArrays(1, &vao)); + GL(glGenBuffers(1, &vbo)); + + GL(glBindVertexArray(vao)); + GL(glBindBuffer(GL_ARRAY_BUFFER, vbo)); + + GL(glBufferData(GL_ARRAY_BUFFER, static_cast(sizeof(core::frame_geometry::coord)) * coords.size(), coords.data(), GL_STATIC_DRAW)); auto stride = static_cast(sizeof(core::frame_geometry::coord)); auto vertex_coord_member = &core::frame_geometry::coord::vertex_x; @@ -383,16 +384,28 @@ struct image_kernel::impl auto vertex_coord_ptr = &(data_ptr->*vertex_coord_member); auto texture_coord_ptr = &(data_ptr->*texture_coord_member); - glVertexPointer(2, GL_DOUBLE, stride, vertex_coord_ptr); - glTexCoordPointer(4, GL_DOUBLE, stride, texture_coord_ptr); + auto vtx_loc = shader_->get_attrib_location("Position"); + auto tex_loc = shader_->get_attrib_location("TexCoordIn"); + + GL(glEnableVertexAttribArray(vtx_loc)); + GL(glEnableVertexAttribArray(tex_loc)); - for (int i = 0; i < coords.size(); i += 4) { - glDrawArrays(GL_QUADS, i, 4); - glTextureBarrier(); + GL(glVertexAttribPointer(vtx_loc, 2, GL_DOUBLE, GL_FALSE, stride, nullptr)); + GL(glVertexAttribPointer(tex_loc, 4, GL_DOUBLE, GL_FALSE, stride, nullptr)); + + for (int i = 0; i < coords.size(); i += 3) { + GL(glDrawArrays(GL_TRIANGLES, i, 3)); + GL(glTextureBarrier()); } - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); + GL(glDisableVertexAttribArray(vtx_loc)); + GL(glDisableVertexAttribArray(tex_loc)); + + GL(glBindVertexArray(0)); + GL(glBindBuffer(GL_ARRAY_BUFFER, 0)); + + GL(glDeleteVertexArrays(1, &vao)); + GL(glDeleteBuffers(1, &vbo)); break; } default: diff --git a/src/accelerator/ogl/image/image_shader.cpp b/src/accelerator/ogl/image/image_shader.cpp index a99b9c9dd6..a9a8455618 100644 --- a/src/accelerator/ogl/image/image_shader.cpp +++ b/src/accelerator/ogl/image/image_shader.cpp @@ -87,7 +87,7 @@ std::string get_blend_color_func() vec4 blend(vec4 fore) { - vec4 back = texture2D(background, gl_TexCoord[1].st).bgra; + vec4 back = texture(background, TexCoord2.st).bgra; if(blend_mode != 0) fore.rgb = get_blend_color(back.rgb/(back.a+0.0000001), fore.rgb/(fore.a+0.0000001))*fore.a; switch(keyer) @@ -118,12 +118,22 @@ std::string get_chroma_func() std::string get_vertex() { return R"shader( + + #version 450 + in vec4 TexCoordIn; + in vec2 Position; + uniform mat4 projTrans; + + out vec4 TexCoord; + out vec4 TexCoord2; + void main() { - gl_TexCoord[0] = gl_MultiTexCoord0; - // gl_TexCoord[1] = gl_MultiTexCoord1; - vec4 pos = ftransform(); - gl_TexCoord[1] = vec4(pos.xy, 0.0, 0.0); + TexCoord = TexCoordIn; + // vec4 pos = ftransform(); + //vec4 pos = projTrans * vec4(Position, 0, 1); + vec4 pos = vec4(Position, 0, 1); + TexCoord2 = vec4(pos.xy, 0.0, 0.0); pos.x = pos.x*2.0 - 1.0; pos.y = pos.y*2.0 - 1.0; gl_Position = pos; @@ -135,7 +145,11 @@ std::string get_fragment() { return R"shader( - #version 130 + #version 450 + in vec4 TexCoord; + in vec4 TexCoord2; + out vec4 fragColor; + uniform sampler2D background; uniform sampler2D plane[4]; uniform sampler2D local_key; @@ -261,39 +275,39 @@ std::string get_fragment() switch(pixel_format) { case 0: //gray - return vec4(get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q).rrr, 1.0); + return vec4(get_sample(plane[0], TexCoord.st).rrr, 1.0); case 1: //bgra, - return get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q).bgra; + return get_sample(plane[0], TexCoord.st).bgra; case 2: //rgba, - return get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q).rgba; + return get_sample(plane[0], TexCoord.st).rgba; case 3: //argb, - return get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q).argb; + return get_sample(plane[0], TexCoord.st).argb; case 4: //abgr, - return get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q).gbar; + return get_sample(plane[0], TexCoord.st).gbar; case 5: //ycbcr, { - float y = get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q).r; - float cb = get_sample(plane[1], gl_TexCoord[0].st / gl_TexCoord[0].q).r; - float cr = get_sample(plane[2], gl_TexCoord[0].st / gl_TexCoord[0].q).r; + float y = get_sample(plane[0], TexCoord.st).r; + float cb = get_sample(plane[1], TexCoord.st).r; + float cr = get_sample(plane[2], TexCoord.st).r; return ycbcra_to_rgba(y, cb, cr, 1.0); } case 6: //ycbcra { - float y = get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q).r; - float cb = get_sample(plane[1], gl_TexCoord[0].st / gl_TexCoord[0].q).r; - float cr = get_sample(plane[2], gl_TexCoord[0].st / gl_TexCoord[0].q).r; - float a = get_sample(plane[3], gl_TexCoord[0].st / gl_TexCoord[0].q).r; + float y = get_sample(plane[0], TexCoord.st).r; + float cb = get_sample(plane[1], TexCoord.st).r; + float cr = get_sample(plane[2], TexCoord.st).r; + float a = get_sample(plane[3], TexCoord.st).r; return ycbcra_to_rgba(y, cb, cr, a); } case 7: //luma { - vec3 y3 = get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q).rrr; + vec3 y3 = get_sample(plane[0], TexCoord.st).rrr; return vec4((y3-0.065)/0.859, 1.0); } case 8: //bgr, - return vec4(get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q).bgr, 1.0); + return vec4(get_sample(plane[0], TexCoord.st).bgr, 1.0); case 9: //rgb, - return vec4(get_sample(plane[0], gl_TexCoord[0].st / gl_TexCoord[0].q).rgb, 1.0); + return vec4(get_sample(plane[0], TexCoord.st).rgb, 1.0); } return vec4(0.0, 0.0, 0.0, 0.0); } @@ -308,13 +322,13 @@ std::string get_fragment() if(csb) color.rgb = ContrastSaturationBrightness(color, brt, sat, con); if(has_local_key) - color *= texture2D(local_key, gl_TexCoord[1].st).r; + color *= texture(local_key, TexCoord2.st).r; if(has_layer_key) - color *= texture2D(layer_key, gl_TexCoord[1].st).r; + color *= texture(layer_key, TexCoord2.st).r; color *= opacity; if (blend_mode >= 0) color = blend(color); - gl_FragColor = color.bgra; + fragColor = color.bgra; } )shader"; } diff --git a/src/accelerator/ogl/util/device.cpp b/src/accelerator/ogl/util/device.cpp index 0a0eaa6477..5120aa66a9 100644 --- a/src/accelerator/ogl/util/device.cpp +++ b/src/accelerator/ogl/util/device.cpp @@ -74,6 +74,7 @@ struct device::impl : public std::enable_shared_from_this impl() : work_(make_work_guard(service_)) + , device_(sf::ContextSettings(0, 0, 0, 4, 5, sf::ContextSettings::Attribute::Core), 1, 1) { CASPAR_LOG(info) << L"Initializing OpenGL Device."; @@ -83,17 +84,17 @@ struct device::impl : public std::enable_shared_from_this CASPAR_THROW_EXCEPTION(gl::ogl_exception() << msg_info("Failed to initialize GLEW.")); } - if (!GLEW_VERSION_4_5) { + version_ = u16(reinterpret_cast(GL2(glGetString(GL_VERSION)))) + L" " + + u16(reinterpret_cast(GL2(glGetString(GL_VENDOR)))); + + CASPAR_LOG(info) << L"Initialized OpenGL " << version(); + + if (!GLEW_VERSION_4_5 && !glewIsSupported("GL_ARB_sync GL_ARB_shader_objects GL_ARB_multitexture GL_ARB_direct_state_access GL_ARB_texture_barrier")) { CASPAR_THROW_EXCEPTION(not_supported() << msg_info("Your graphics card does not meet the minimum hardware requirements " "since it does not support OpenGL 4.5 or higher.")); } - version_ = u16(reinterpret_cast(GL2(glGetString(GL_VERSION)))) + L" " + - u16(reinterpret_cast(GL2(glGetString(GL_VENDOR)))); - - CASPAR_LOG(info) << L"Successfully initialized OpenGL " << version(); - GL(glCreateFramebuffers(1, &fbo_)); GL(glBindFramebuffer(GL_FRAMEBUFFER, fbo_)); diff --git a/src/accelerator/ogl/util/shader.cpp b/src/accelerator/ogl/util/shader.cpp index d6d6a7d45e..7a35f7dbf0 100644 --- a/src/accelerator/ogl/util/shader.cpp +++ b/src/accelerator/ogl/util/shader.cpp @@ -31,7 +31,8 @@ namespace caspar { namespace accelerator { namespace ogl { struct shader::impl : boost::noncopyable { GLuint program_; - std::unordered_map locations_; + std::unordered_map uniform_locations_; + std::unordered_map attrib_locations_; public: impl(const std::string& vertex_source_str, const std::string& fragment_source_str) @@ -97,28 +98,36 @@ struct shader::impl : boost::noncopyable ~impl() { glDeleteProgram(program_); } - GLint get_location(const char* name) + GLint get_uniform_location(const char* name) { - auto it = locations_.find(name); - if (it == locations_.end()) - it = locations_.insert(std::make_pair(name, glGetUniformLocation(program_, name))).first; + auto it = uniform_locations_.find(name); + if (it == uniform_locations_.end()) + it = uniform_locations_.insert(std::make_pair(name, glGetUniformLocation(program_, name))).first; + return it->second; + } + + GLint get_attrib_location(const char* name) + { + auto it = attrib_locations_.find(name); + if (it == attrib_locations_.end()) + it = attrib_locations_.insert(std::make_pair(name, glGetAttribLocation(program_, name))).first; return it->second; } void set(const std::string& name, bool value) { set(name, value ? 1 : 0); } - void set(const std::string& name, int value) { GL(glUniform1i(get_location(name.c_str()), value)); } + void set(const std::string& name, int value) { GL(glUniform1i(get_uniform_location(name.c_str()), value)); } - void set(const std::string& name, float value) { GL(glUniform1f(get_location(name.c_str()), value)); } + void set(const std::string& name, float value) { GL(glUniform1f(get_uniform_location(name.c_str()), value)); } void set(const std::string& name, double value0, double value1) { - GL(glUniform2f(get_location(name.c_str()), static_cast(value0), static_cast(value1))); + GL(glUniform2f(get_uniform_location(name.c_str()), static_cast(value0), static_cast(value1))); } void set(const std::string& name, double value) { - GL(glUniform1f(get_location(name.c_str()), static_cast(value))); + GL(glUniform1f(get_uniform_location(name.c_str()), static_cast(value))); } void use() { GL(glUseProgramObjectARB(program_)); } @@ -134,6 +143,7 @@ void shader::set(const std::string& name, int value) { impl_->set(name, value); void shader::set(const std::string& name, float value) { impl_->set(name, value); } void shader::set(const std::string& name, double value0, double value1) { impl_->set(name, value0, value1); } void shader::set(const std::string& name, double value) { impl_->set(name, value); } +GLint shader::get_attrib_location(const char* name) { return impl_->get_attrib_location(name); } int shader::id() const { return impl_->program_; } void shader::use() const { impl_->use(); } diff --git a/src/accelerator/ogl/util/shader.h b/src/accelerator/ogl/util/shader.h index f0e9afc594..615b33fb36 100644 --- a/src/accelerator/ogl/util/shader.h +++ b/src/accelerator/ogl/util/shader.h @@ -42,6 +42,8 @@ class shader final void set(const std::string& name, double value0, double value1); void set(const std::string& name, double value); + GLint get_attrib_location(const char* name); + template typename std::enable_if::value, void>::type set(const std::string& name, E value) { diff --git a/src/core/frame/geometry.cpp b/src/core/frame/geometry.cpp index 7420067305..f347932e97 100644 --- a/src/core/frame/geometry.cpp +++ b/src/core/frame/geometry.cpp @@ -43,13 +43,10 @@ struct frame_geometry::impl impl(frame_geometry::geometry_type type, std::vector data) : type_(type) { - if (type == geometry_type::quad && data.size() != 4) - CASPAR_THROW_EXCEPTION(invalid_argument() << msg_info("The number of coordinates needs to be 4")); - - if (type == geometry_type::quad_list) { - if (data.size() % 4 != 0) + if (type == geometry_type::triangles) { + if (data.size() % 3 != 0) CASPAR_THROW_EXCEPTION(invalid_argument() - << msg_info("The number of coordinates needs to be a multiple of 4")); + << msg_info("The number of coordinates needs to be a multiple of 3")); } data_ = std::move(data); @@ -74,9 +71,11 @@ const frame_geometry& frame_geometry::get_default() {0.0, 0.0, 0.0, 0.0}, // upper left {1.0, 0.0, 1.0, 0.0}, // upper right {1.0, 1.0, 1.0, 1.0}, // lower right + {0.0, 0.0, 0.0, 0.0}, // upper left + {1.0, 1.0, 1.0, 1.0}, // lower right {0.0, 1.0, 0.0, 1.0} // lower left }; - static const frame_geometry g(frame_geometry::geometry_type::quad, data); + static const frame_geometry g(frame_geometry::geometry_type::triangles, data); return g; } diff --git a/src/core/frame/geometry.h b/src/core/frame/geometry.h index 1996972d87..94ed7c80bc 100644 --- a/src/core/frame/geometry.h +++ b/src/core/frame/geometry.h @@ -32,8 +32,7 @@ class frame_geometry public: enum class geometry_type { - quad, - quad_list + triangles }; struct coord diff --git a/src/modules/screen/consumer/screen_consumer.cpp b/src/modules/screen/consumer/screen_consumer.cpp index 6f0a0e8b8e..288181bdf5 100644 --- a/src/modules/screen/consumer/screen_consumer.cpp +++ b/src/modules/screen/consumer/screen_consumer.cpp @@ -90,6 +90,7 @@ struct frame { GLuint pbo = 0; GLuint tex = 0; + GLuint fbo = 0; char* ptr = nullptr; GLsync fence = 0; }; @@ -179,7 +180,7 @@ struct screen_consumer : boost::noncopyable auto window_style = config_.borderless ? sf::Style::None : (config_.windowed ? sf::Style::Resize | sf::Style::Close : sf::Style::Fullscreen); - window_.create(sf::VideoMode::getDesktopMode(), u8(print()), window_style); + window_.create(sf::VideoMode::getDesktopMode(), u8(print()), window_style, sf::ContextSettings(0, 0, 0, 4, 5, sf::ContextSettings::Attribute::Core)); window_.setPosition(sf::Vector2i(screen_x_, screen_y_)); window_.setSize(sf::Vector2u(screen_width_, screen_height_)); window_.setMouseCursorVisible(config_.interactive); @@ -189,8 +190,10 @@ struct screen_consumer : boost::noncopyable CASPAR_THROW_EXCEPTION(gl::ogl_exception() << msg_info("Failed to initialize GLEW.")); } - if (!GLEW_VERSION_4_5) { - CASPAR_THROW_EXCEPTION(not_supported() << msg_info("Missing OpenGL 4.5 support.")); + if (!GLEW_VERSION_4_5 && !glewIsSupported("GL_ARB_sync GL_ARB_shader_objects GL_ARB_multitexture GL_ARB_direct_state_access GL_ARB_texture_barrier")) { + CASPAR_THROW_EXCEPTION(not_supported() + << msg_info("Your graphics card does not meet the minimum hardware requirements " + "since it does not support OpenGL 4.5 or higher.")); } for (int n = 0; n < 2; ++n) { @@ -204,19 +207,21 @@ struct screen_consumer : boost::noncopyable GL(glCreateTextures(GL_TEXTURE_2D, 1, &frame.tex)); GL(glTextureParameteri(frame.tex, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); GL(glTextureParameteri(frame.tex, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); - GL(glTextureParameteri(frame.tex, GL_TEXTURE_WRAP_S, GL_CLAMP)); - GL(glTextureParameteri(frame.tex, GL_TEXTURE_WRAP_T, GL_CLAMP)); + GL(glTextureParameteri(frame.tex, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); + GL(glTextureParameteri(frame.tex, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); GL(glTextureStorage2D(frame.tex, 1, GL_RGBA8, format_desc_.width, format_desc_.height)); GL(glClearTexImage(frame.tex, 0, GL_BGRA, GL_UNSIGNED_BYTE, nullptr)); + GL(glCreateFramebuffers(1, &frame.fbo)); + GL(glBindFramebuffer(GL_READ_FRAMEBUFFER, frame.fbo)); + GL(glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, frame.tex, 0)); + frames_.push_back(frame); } - GL(glEnable(GL_TEXTURE_2D)); GL(glDisable(GL_DEPTH_TEST)); GL(glClearColor(0.0, 0.0, 0.0, 0.0)); GL(glViewport(0, 0, format_desc_.width, format_desc_.height)); - GL(glLoadIdentity()); calculate_aspect(); @@ -238,6 +243,7 @@ struct screen_consumer : boost::noncopyable for (auto frame : frames_) { GL(glUnmapNamedBuffer(frame.pbo)); glDeleteBuffers(1, &frame.pbo); + glDeleteFramebuffers(1, &frame.fbo); glDeleteTextures(1, &frame.tex); } window_.close(); @@ -323,22 +329,13 @@ struct screen_consumer : boost::noncopyable { auto& frame = frames_.back(); - GL(glBindTexture(GL_TEXTURE_2D, frame.tex)); GL(glClear(GL_COLOR_BUFFER_BIT)); - // TODO (perf) - glBegin(GL_QUADS); - glTexCoord2f(0.0f, 1.0f); - glVertex2f(-width_, -height_); - glTexCoord2f(1.0f, 1.0f); - glVertex2f(width_, -height_); - glTexCoord2f(1.0f, 0.0f); - glVertex2f(width_, height_); - glTexCoord2f(0.0f, 0.0f); - glVertex2f(-width_, height_); - glEnd(); - - GL(glBindTexture(GL_TEXTURE_2D, 0)); + GL(glBindFramebuffer(GL_READ_FRAMEBUFFER, frame.fbo)); + GL(glBlitFramebuffer(0, 0, format_desc_.width, format_desc_.height, + 0, screen_height_, screen_width_, 0, + GL_COLOR_BUFFER_BIT, GL_LINEAR)); + GL(glBindFramebuffer(GL_READ_FRAMEBUFFER, 0)); } window_.display();