私がしようとしているのは、ユーザーが画面を切り替えるか、全画面表示からウィンドウ表示に切り替えるか、その他の任意の数のために発生する可能性のある、新しいウィンドウでレンダリングしているウィンドウを置き換える場合です理由。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;
}
ように、コードの現在のバージョンは、次を行うことになっている:
- プライマリモニタ 上のフルスクリーンウィンドウを表示します
- このモニターでは、マジェンタと青の間で時間の経過とともに「正方形」(矩形、本当に....)が表示され、t彼はマゼンタと緑の色の間の背景を背景にしています。
- ユーザーがキーを押すと、最初のウィンドウのコンテキストを使用してGLFWのウィンドウ作成にフィードする新しいフルスクリーンウィンドウを2番目のモニターに作成し、元のウィンドウを破棄します(この順序で)
- これに同じ矩形を表示します第2のウィンドウ
- 定期的にバックグラウンドの遷移を続ける
- ユーザーがキーをもう一度押すと、2番目のウィンドウを破棄してプログラムを終了します。
これらの手順のうち、手順4はまったく機能しません。手順3は部分的に機能します。ウィンドウは作成されますが、デフォルトでは表示されず、ユーザーはタスクバー。両方のウィンドウの背景を遷移させるなど、他のすべてのステップは期待通りに機能します。
私の前提は、コンテキスト間のオブジェクトの共有に関して何かが間違っていることです。具体的には、私が作成している2番目のコンテキストが最初のコンテキストによって作成されたオブジェクトを受け取っているようには見えません。私が作っている明らかな論理エラーはありますか?コンテキストの共有が意図どおりに機能するようにするために他の何かをしなければならないでしょうか? GLFWにバグがある可能性はありますか?
何が共有されるのか、何が共有されないのかを正確に議論する包括的なフォーラムまたはブログの投稿はありますか?私はそれを理解するために[OpenGL spec](https://www.opengl.org/registry/doc/glspec45.core.pdf)(第5章)を読んでみましたが、私にとってはあまりにも難解です。 私は、ウィンドウを破壊する必要がないようにコードを書き直すつもりですが、次のステップは複数のウィンドウを同時にレンダリングする作業です同じオブジェクトを使用しているため、コンテキスト共有の不具合から逃れることはできません。 – Xirema
スペックは別として、私は良い説明は分かりません。複数のウィンドウに対して複数のコンテキストが必要なわけではなく、同じコンテキストを持つウィンドウの後ろに1つのウィンドウを使用することもできます。また、このようなコンテキスト切り替えを少なくするような新しい拡張があります(ただし、それに値するだろう)。 – derhass
よろしくお願いします。私は仕様を凝視してより多くの時間を費やすでしょう。その間、 'glfwSetWindowMonitor'と他の同様の関数を使うためにこのコードを書き直すことは私の問題を解決したので、私はこの答えを受け入れます。 – Xirema