|  | // 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 <cstdio> | 
|  | #include "GLFW/glfw3.h" | 
|  |  | 
|  | namespace backend { namespace opengl { | 
|  | void Init(void* (*getProc)(const char*), dawnProcTable* procs, dawnDevice* device); | 
|  | }}  // namespace backend::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); | 
|  | backend::opengl::Init(reinterpret_cast<void* (*)(const char*)>(glfwGetProcAddress), | 
|  | procs, device); | 
|  |  | 
|  | mBackendDevice = *device; | 
|  | } | 
|  |  | 
|  | uint64_t GetSwapChainImplementation() override { | 
|  | if (mSwapchainImpl.userData == nullptr) { | 
|  | mSwapchainImpl = CreateSwapChainImplementation(new SwapChainImplGL(mWindow)); | 
|  | } | 
|  | return reinterpret_cast<uint64_t>(&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 |