2016-12-04 8 views
0

내가하려고하는 것은 사용자가 화면을 전환하거나 화면 전체를 창으로 전환했거나 다른 숫자로 전환하여 발생할 수있는 새 창으로 렌더링하는 창을 대체 할 수 있도록하는 것입니다. 원인.GLFW를 사용하여 컨텍스트 공유를 올바르게 수행하는 방법은 무엇입니까?

내 코드는 지금까지 다음과 같습니다

"Context.h"

struct window_deleter { 
    void operator()(GLFWwindow * window) const; 
}; 

class context { 
    std::unique_ptr<GLFWwindow, window_deleter> window; 
public: 
    context(int width, int height, const char * s, GLFWmonitor * monitor, GLFWwindow * old_window, bool borderless); 
    GLFWwindow * get_window() const; 
    void make_current() const; 
}; 

"Context.cpp"

context::context(int width, int height, const char * s, GLFWmonitor * monitor, GLFWwindow * old_window, bool borderless) { 
    if (!glfwInit()) throw std::runtime_error("Unable to Initialize GLFW"); 
    if (borderless) glfwWindowHint(GLFW_DECORATED, 0); 
    else glfwWindowHint(GLFW_DECORATED, 1); 
    window.reset(glfwCreateWindow(width, height, s, monitor, old_window)); 
    if (!window) throw std::runtime_error("Unable to Create Window"); 
    make_current(); 
} 

GLFWwindow * context::get_window() const { 
    return window.get(); 
} 

void context::make_current() const { 
    glfwMakeContextCurrent(window.get()); 
} 

"WindowManager.h을"

#include "Context.h" 
class window_style; 
/* window_style is basically a really fancy "enum class", and I don't 
* believe its implementation or interface are relevant to this project. 
* I'll add it if knowing how it works is super critical. 
*/ 

class window_manager { 
    context c_context; 
    uint32_t c_width, c_height; 
    std::string c_title; 
    window_style c_style; 
    std::function<bool()> close_test; 
    std::function<void()> poll_task; 
public: 
    static GLFWmonitor * get_monitor(window_style style); 
    window_manager(uint32_t width, uint32_t height, std::string const& title, window_style style); 
    context & get_context(); 
    const context & get_context() const; 
    bool resize(uint32_t width, uint32_t height, std::string const& title, window_style style); 
    std::function<bool()> get_default_close_test(); 
    void set_close_test(std::function<bool()> const& test); 
    std::function<void()> get_default_poll_task(); 
    void set_poll_task(std::function<void()> const& task); 

    void poll_loop(); 
}; 

"WindowManager.cpp"

GLFWmonitor * window_manager::get_monitor(window_style style) { 
    if (style.type != window_style::style_type::fullscreen) return nullptr; 
    if (!glfwInit()) throw std::runtime_error("Unable to initialize GLFW"); 
    int count; 
    GLFWmonitor ** monitors = glfwGetMonitors(&count); 
    if (style.monitor_number >= uint32_t(count)) throw invalid_monitor_exception{}; 
    return monitors[style.monitor_number]; 
} 

std::function<bool()> window_manager::get_default_close_test() { 
    return [&] {return glfwWindowShouldClose(c_context.get_window()) != 0; }; 
} 

window_manager::window_manager(uint32_t width, uint32_t height, std::string const& title, window_style style) : 
c_context(int(width), int(height), title.c_str(), get_monitor(style), nullptr, style.type == window_style::style_type::borderless), 
    c_width(width), c_height(height), c_title(title), c_style(style), close_test(get_default_close_test()), poll_task(get_default_poll_task()) { 
} 
context & window_manager::get_context() { 
    return c_context; 
} 
const context & window_manager::get_context() const { 
    return c_context; 
} 

bool window_manager::resize(uint32_t width, uint32_t height, std::string const& title, window_style style) { 
    if (width == c_width && height == c_height && title == c_title && style == c_style) return false; 
    c_width = width; 
    c_height = height; 
    c_title = title; 
    c_style = style; 
    c_context = context(int(width), int(height), title.c_str(), get_monitor(style), get_context().get_window(), style.type == window_style::style_type::borderless); 
    return true; 
} 

void window_manager::set_close_test(std::function<bool()> const& test) { 
    close_test = test; 
} 

std::function<void()> window_manager::get_default_poll_task() { 
    return [&] {glfwSwapBuffers(c_context.get_window()); }; 
} 

void window_manager::set_poll_task(std::function<void()> const& task) { 
    poll_task = task; 
} 

void window_manager::poll_loop() { 
    while (!close_test()) { 
     glfwPollEvents(); 
     poll_task(); 
    } 
} 

"하여 Main.cpp"

int main() { 
    try { 
     glfwInit(); 
     const GLFWvidmode * vid_mode = glfwGetVideoMode(glfwGetPrimaryMonitor()); 
     gl_backend::window_manager window(vid_mode->width, vid_mode->height, "First test of the window manager", gl_backend::window_style::fullscreen(0)); 
     glfwSetKeyCallback(window.get_context().get_window(), [](GLFWwindow * window, int, int, int, int) {glfwSetWindowShouldClose(window, 1); }); 
     glbinding::Binding::initialize(); 
     //Anything with a "glresource" prefix is basically just a std::shared_ptr<GLuint> 
     //with some extra deletion code added. 
     glresource::vertex_array vao; 
     glresource::buffer square; 
     float data[] = { 
      -.5f, -.5f, 
      .5f, -.5f, 
      .5f, .5f, 
      -.5f, .5f 
     }; 
     gl::glBindVertexArray(*vao); 
     gl::glBindBuffer(gl::GL_ARRAY_BUFFER, *square); 
     gl::glBufferData(gl::GL_ARRAY_BUFFER, sizeof(data), data, gl::GL_STATIC_DRAW); 
     gl::glEnableVertexAttribArray(0); 
     gl::glVertexAttribPointer(0, 2, gl::GL_FLOAT, false, 2 * sizeof(float), nullptr); 

     std::string vert_src = 
      "#version 430\n" 
      "layout(location = 0) in vec2 vertices;" 
      "void main() {" 
      "gl_Position = vec4(vertices, 0, 1);" 
      "}"; 

     std::string frag_src = 
      "#version 430\n" 
      "uniform vec4 square_color;" 
      "out vec4 fragment_color;" 
      "void main() {" 
      "fragment_color = square_color;" 
      "}"; 
     glresource::shader vert(gl::GL_VERTEX_SHADER, vert_src); 
     glresource::shader frag(gl::GL_FRAGMENT_SHADER, frag_src); 
     glresource::program program({ vert, frag }); 
     window.set_poll_task([&] { 
      gl::glUseProgram(*program); 
      gl::glBindVertexArray(*vao); 
      glm::vec4 color{ (glm::sin(float(glfwGetTime())) + 1)/2, 0.f, 0.5f, 1.f }; 
      gl::glUniform4fv(gl::glGetUniformLocation(*program, "square_color"), 1, glm::value_ptr(color)); 
      gl::glDrawArrays(gl::GL_QUADS, 0, 4); 
      glfwSwapBuffers(window.get_context().get_window()); 
     }); 
     window.poll_loop(); 
     window.resize(vid_mode->width, vid_mode->height, "Second test of the window manager", gl_backend::window_style::fullscreen(1)); 
     glfwSetKeyCallback(window.get_context().get_window(), [](GLFWwindow * window, int, int, int, int) {glfwSetWindowShouldClose(window, 1); }); 
     window.poll_loop(); 
    } 
    catch (std::exception const& e) { 
     std::cerr << e.what() << std::endl; 
     std::ofstream error_log("error.log"); 
     error_log << e.what() << std::endl; 
     system("pause"); 
    } 
    return 0; 
} 

그래서 코드의 현재 버전은 다음 어떻게해야 입니다 :

  1. 디스플레이 기본 모니터
  2. 에 전체 화면 창
  3. 이 모니터에서는 마젠타와 파랑 사이의 시간이 지남에 따라 변하는 "사각형"(직사각형, 정말로 ....)을 표시하고 t 그는 마젠타 색과 초록색 사이의 배경 전환을합니다.
  4. 사용자가 키를 누르면 두 번째 모니터에서 첫 번째 창 컨텍스트를 사용하여 GLFW 창의 창에 새 전체 화면 창을 만들고 원래 창을 순서대로 파괴합니다.
  5. 동일한 사각형을이 위에 표시하십시오 두 번째 창
  6. 주기적으로 배경을 계속 전환하십시오.
  7. 사용자가 키를 다시 누르면 두 번째 창을 파괴하고 프로그램을 종료하십시오.

이 단계 중 4 단계가 전혀 작동하지 않고 3 단계가 부분적으로 작동합니다. 창은 생성되지만 기본적으로 표시되지 않으며 사용자는 작업 표시 줄. 두 단계의 전환 배경을 포함하여 다른 모든 단계는 예상대로 작동합니다.

그래서 내 가정은 컨텍스트간에 공유되는 개체와 관련해서 뭔가 잘못되어 가고 있다는 것입니다. 특히, 내가 만드는 두 번째 컨텍스트가 첫 번째 컨텍스트에 의해 생성 된 개체를받는 것으로 나타나지 않습니다. 내가 만드는 확실한 논리 오류가 있습니까? 컨텍스트 공유가 의도 한대로 작동하는지 확인하기 위해 다른 작업을해야합니까? GLFW에 버그가있을 수 있습니까?

답변

3

내 가정은 컨텍스트 사이의 개체 공유와 관련해서 뭔가 잘못 될 수 있다는 것입니다. 특히, 내가 만드는 두 번째 컨텍스트가 첫 번째 컨텍스트에 의해 생성 된 개체를받는 것으로 나타나지 않습니다. 내가 만드는 확실한 논리 오류가 있습니까?

네 전제가 잘못되었습니다.공유 OpenGL 컨텍스트는 전체 상태, VBO, 텍스처, 쉐이더 및 프로그램, 렌더 버퍼 등과 같은 사용자 고유 데이터를 실제로 보유하는 "큰"객체 만 공유하며 상태 컨테이너는 참조하지 않습니다 VAOs, FBOs와 같은 것들은 절대 공유되지 않습니다.

컨텍스트 공유가 의도 한대로 작동하는지 확인해야합니까?

글쎄, 당신이 정말 그 길을 가고 싶어, 당신은 모든 상태 컨테이너를 재 구축하고, 또한 글로벌 상태 (모든 glEnable의, 깊이 버퍼 설정, 혼합 상태의 톤을 복원해야 다른 것들).

그러나 귀하의 전체 개념이 의심 스럽습니다. 전체 화면에서 창으로 이동하거나 동일한 GPU의 다른 모니터로 이동할 때 창을 지울 필요가 없습니다. GLFW는 glfwSetWindowMonitor()을 통해이를 직접 지원합니다.

그리고 을 실행해도은 창을 다시 작성한다고해서 GL 문맥을 다시 만들어야하는 것은 아닙니다. GLFW API가 부과하는 제한 사항이있을 수 있지만 기본 개념은 별도입니다. 기본적으로 새 창에서 이전 컨텍스트를 현재 상태로 만들 수 있습니다. GLFW는 Window와 Context를 함께 inseperably 연결합니다. 이것은 불행한 추상화의 일종입니다.

그러나 창을 다시 만드는 것이 필요한 곳은 어디 까지나 상상할 수있는 시나리오 일뿐입니다. 서로 다른 화면이 서로 다른 GPU가 될 수 있습니다. 그러나 GL 컨텍스트 공유는 다른 GL 구현에서 작동하지 않습니다. 전체 컨텍스트 상태를 다시 작성해야합니다.

+0

공유되는 대상과 공유되지 않는 대상을 정확히 논의하는 포괄적 인 포럼 또는 블로그 게시물이 있습니까? 나는 그것을 이해하기 위해 [OpenGL spec] (https://www.opengl.org/registry/doc/glspec45.core.pdf) (제 5 장)을 읽으려고 노력했지만, 그것은 나에게 너무 모호하다. 윈도우를 파괴 할 필요가 없도록 코드를 다시 작성하려고합니다. 그러나 다음 단계는 동시에 여러 윈도우를 렌더링하는 작업을하기 때문에 문제는 관련성을 유지할 것입니다. 동일한 객체를 사용하기 때문에 컨텍스트 공유의 버그 베어를 벗어날 수 없게됩니다. – Xirema

+0

사양 외에도 좋은 설명을 모르겠습니다. 여러 창에 대해 다중 컨텍스트가 반드시 필요한 것은 아니며, 동일한 컨텍스트를 사용하는 다른 창 뒤에 하나의 창을 사용할 수도 있습니다. 이러한 컨텍스트 스위칭을 줄이기위한 몇 가지 새로운 확장이 있습니다 (단, 그만한 가치가있을 것이다). – derhass

+0

좋아. 나는 스펙을 응시하는 데 더 많은 시간을 할애 할 것이다. 그 동안,'glfwSetWindowMonitor'와 다른 비슷한 함수를 사용하기 위해이 코드를 다시 작성하면 내 문제가 해결되었으므로이 대답을 받아 들일 것입니다. – Xirema

관련 문제