// Copyright 2017 The Dawn Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "utils/BackendBinding.h" #include "common/Assert.h" #include "common/Platform.h" #include "common/SwapChainUtils.h" #include "dawn/dawn_wsi.h" // Glad needs to be included before GLFW otherwise it complain that GL.h was already included #include "glad/glad.h" #include #include "GLFW/glfw3.h" namespace dawn_native { namespace opengl { void Init(void* (*getProc)(const char*), dawnProcTable* procs, dawnDevice* device); }} // namespace dawn_native::opengl namespace utils { class SwapChainImplGL { public: using WSIContext = dawnWSIContextGL; SwapChainImplGL(GLFWwindow* window) : mWindow(window) { } ~SwapChainImplGL() { glDeleteTextures(1, &mBackTexture); glDeleteFramebuffers(1, &mBackFBO); } void Init(dawnWSIContextGL*) { glGenTextures(1, &mBackTexture); glBindTexture(GL_TEXTURE_2D, mBackTexture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); glGenFramebuffers(1, &mBackFBO); glBindFramebuffer(GL_READ_FRAMEBUFFER, mBackFBO); glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mBackTexture, 0); } dawnSwapChainError Configure(dawnTextureFormat format, dawnTextureUsageBit, uint32_t width, uint32_t height) { if (format != DAWN_TEXTURE_FORMAT_R8_G8_B8_A8_UNORM) { return "unsupported format"; } ASSERT(width > 0); ASSERT(height > 0); mWidth = width; mHeight = height; glBindTexture(GL_TEXTURE_2D, mBackTexture); // Reallocate the texture glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); return DAWN_SWAP_CHAIN_NO_ERROR; } dawnSwapChainError GetNextTexture(dawnSwapChainNextTexture* nextTexture) { nextTexture->texture.u32 = mBackTexture; return DAWN_SWAP_CHAIN_NO_ERROR; } dawnSwapChainError Present() { glBindFramebuffer(GL_READ_FRAMEBUFFER, mBackFBO); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glBlitFramebuffer(0, 0, mWidth, mHeight, 0, mHeight, mWidth, 0, GL_COLOR_BUFFER_BIT, GL_NEAREST); glfwSwapBuffers(mWindow); return DAWN_SWAP_CHAIN_NO_ERROR; } private: GLFWwindow* mWindow = nullptr; uint32_t mWidth = 0; uint32_t mHeight = 0; GLuint mBackFBO = 0; GLuint mBackTexture = 0; }; class OpenGLBinding : public BackendBinding { public: void SetupGLFWWindowHints() override { #if defined(DAWN_PLATFORM_APPLE) glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); #else glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4); glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); #endif } void GetProcAndDevice(dawnProcTable* procs, dawnDevice* device) override { glfwMakeContextCurrent(mWindow); dawn_native::opengl::Init(reinterpret_cast(glfwGetProcAddress), procs, device); mBackendDevice = *device; } uint64_t GetSwapChainImplementation() override { if (mSwapchainImpl.userData == nullptr) { mSwapchainImpl = CreateSwapChainImplementation(new SwapChainImplGL(mWindow)); } return reinterpret_cast(&mSwapchainImpl); } dawnTextureFormat GetPreferredSwapChainTextureFormat() override { return DAWN_TEXTURE_FORMAT_R8_G8_B8_A8_UNORM; } private: dawnDevice mBackendDevice = nullptr; dawnSwapChainImplementation mSwapchainImpl = {}; }; BackendBinding* CreateOpenGLBinding() { return new OpenGLBinding; } } // namespace utils