mirror of
				https://bitbucket.org/chromiumembedded/cef
				synced 2025-06-05 21:39:12 +02:00 
			
		
		
		
	Add "cef/" prefix for CEF #includes in libcef/ directory. Sort #includes by following https://google.github.io/styleguide/cppguide.html#Names_and_Order_of_Includes
		
			
				
	
	
		
			343 lines
		
	
	
		
			9.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			343 lines
		
	
	
		
			9.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Copyright 2018 The Chromium Embedded Framework Authors. All rights reserved.
 | |
| // Use of this source code is governed by a BSD-style license that can be
 | |
| // found in the LICENSE file.
 | |
| 
 | |
| #include "cef/libcef/browser/gpu/external_texture_manager.h"
 | |
| 
 | |
| #include "gpu/command_buffer/service/service_utils.h"
 | |
| #include "third_party/khronos/EGL/egl.h"
 | |
| #include "third_party/khronos/EGL/eglext.h"
 | |
| #include "ui/gl/gl_bindings.h"
 | |
| #include "ui/gl/gl_context_egl.h"
 | |
| #include "ui/gl/gl_image.h"
 | |
| #include "ui/gl/gl_surface_egl.h"
 | |
| #include "ui/gl/init/gl_factory.h"
 | |
| 
 | |
| #if BUILDFLAG(IS_WIN)
 | |
| #include <d3d11_1.h>
 | |
| 
 | |
| #include "ui/gl/gl_angle_util_win.h"
 | |
| #include "ui/gl/gl_image_dxgi.h"
 | |
| #endif
 | |
| 
 | |
| #ifndef EGL_ANGLE_d3d_texture_client_buffer
 | |
| #define EGL_ANGLE_d3d_texture_client_buffer 1
 | |
| #define EGL_D3D_TEXTURE_ANGLE 0x33A3
 | |
| #endif
 | |
| 
 | |
| namespace gpu {
 | |
| namespace gles2 {
 | |
| 
 | |
| namespace {
 | |
| 
 | |
| #if BUILDFLAG(IS_WIN)
 | |
| 
 | |
| class GLImageDXGISharedHandle : public gl::GLImageDXGI {
 | |
|  public:
 | |
|   GLImageDXGISharedHandle(const gfx::Size& size)
 | |
|       : GLImageDXGI(size, nullptr),
 | |
|         handle_((HANDLE)0),
 | |
|         surface_(EGL_NO_SURFACE),
 | |
|         texture_id_(0) {}
 | |
| 
 | |
|   void* share_handle() const { return handle_; }
 | |
| 
 | |
|   bool Initialize() {
 | |
|     Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
 | |
|         gl::QueryD3D11DeviceObjectFromANGLE();
 | |
|     if (!d3d11_device) {
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     Microsoft::WRL::ComPtr<ID3D11Device1> d3d11_device1;
 | |
|     HRESULT hr = d3d11_device.As(&d3d11_device1);
 | |
|     if (FAILED(hr)) {
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     D3D11_TEXTURE2D_DESC td = {0};
 | |
|     td.ArraySize = 1;
 | |
|     td.CPUAccessFlags = 0;
 | |
|     td.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
 | |
|     td.Width = GetSize().width();
 | |
|     td.Height = GetSize().height();
 | |
|     td.MipLevels = 1;
 | |
|     td.SampleDesc.Count = 1;
 | |
|     td.SampleDesc.Quality = 0;
 | |
|     td.Usage = D3D11_USAGE_DEFAULT;
 | |
|     td.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
 | |
|     td.MiscFlags = 0;
 | |
| 
 | |
|     hr = d3d11_device1->CreateTexture2D(&td, nullptr, texture_.GetAddressOf());
 | |
|     if (FAILED(hr)) {
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     // Create a staging texture that will not be a render-target, but will be
 | |
|     // shared.  We could make the render target directly shareable, but the
 | |
|     // staged copy is safer for synchronization and less problematic
 | |
|     td.BindFlags = D3D11_BIND_SHADER_RESOURCE;
 | |
|     td.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
 | |
|     hr = d3d11_device1->CreateTexture2D(&td, nullptr,
 | |
|                                         staging_texture_.GetAddressOf());
 | |
|     if (FAILED(hr)) {
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     // If using a staging texture ... then we need the shared handle for that
 | |
|     Microsoft::WRL::ComPtr<IDXGIResource> dxgi_res;
 | |
|     if (staging_texture_.Get()) {
 | |
|       hr = staging_texture_.As(&dxgi_res);
 | |
|     } else {
 | |
|       hr = texture_.As(&dxgi_res);
 | |
|     }
 | |
|     if (SUCCEEDED(hr)) {
 | |
|       dxgi_res->GetSharedHandle(&handle_);
 | |
|     }
 | |
| 
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   void Lock() {
 | |
|     // In the future a keyed mutex could be utilized here.
 | |
|   }
 | |
| 
 | |
|   void Unlock() {
 | |
|     if (staging_texture_.Get() && texture_.Get()) {
 | |
|       Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device;
 | |
|       staging_texture_->GetDevice(&d3d11_device);
 | |
|       if (d3d11_device.Get()) {
 | |
|         Microsoft::WRL::ComPtr<ID3D11DeviceContext> d3d11_ctx;
 | |
|         d3d11_device->GetImmediateContext(&d3d11_ctx);
 | |
|         if (d3d11_ctx.Get()) {
 | |
|           d3d11_ctx->CopyResource(staging_texture_.Get(), texture_.Get());
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   void SetSurface(EGLSurface surface, GLuint texture_id) {
 | |
|     surface_ = surface;
 | |
|     texture_id_ = texture_id;
 | |
|   }
 | |
| 
 | |
|   EGLSurface surface() const { return surface_; }
 | |
| 
 | |
|   GLuint texture_id() const { return texture_id_; }
 | |
| 
 | |
|  protected:
 | |
|   ~GLImageDXGISharedHandle() override {}
 | |
| 
 | |
|  private:
 | |
|   HANDLE handle_;
 | |
|   Microsoft::WRL::ComPtr<ID3D11Texture2D> staging_texture_;
 | |
|   EGLSurface surface_;
 | |
|   GLuint texture_id_;
 | |
| };
 | |
| 
 | |
| #endif  // BUILDFLAG(IS_WIN)
 | |
| 
 | |
| }  // namespace
 | |
| 
 | |
| ExternalTextureManager::ExternalTextureManager() {}
 | |
| 
 | |
| ExternalTextureManager::~ExternalTextureManager() {}
 | |
| 
 | |
| void* ExternalTextureManager::CreateTexture(GLuint texture_id,
 | |
|                                             uint32_t width,
 | |
|                                             uint32_t height,
 | |
|                                             TextureManager* tex_man) {
 | |
|   void* share_handle = nullptr;
 | |
| 
 | |
| #if BUILDFLAG(IS_WIN)
 | |
|   EGLDisplay egl_display = gl::GLSurfaceEGL::GetHardwareDisplay();
 | |
|   if (egl_display == EGL_NO_DISPLAY) {
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   EGLContext curContext = eglGetCurrentContext();
 | |
|   if (curContext == EGL_NO_CONTEXT) {
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   gfx::Size size(width, height);
 | |
|   scoped_refptr<gl::GLImage> image;
 | |
|   void* texture = nullptr;
 | |
| 
 | |
|   GLImageDXGISharedHandle* dxgi_image = new GLImageDXGISharedHandle(size);
 | |
|   if (!dxgi_image->Initialize()) {
 | |
|     return nullptr;
 | |
|   }
 | |
|   image = dxgi_image;
 | |
|   share_handle = dxgi_image->share_handle();
 | |
|   texture = dxgi_image->texture().Get();
 | |
| 
 | |
|   if (!image) {  // this check seems unnecessary
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   EGLint numConfigs = 0;
 | |
|   EGLint configAttrs[] = {
 | |
|       EGL_RENDERABLE_TYPE,
 | |
|       EGL_OPENGL_ES3_BIT,  // must remain in this position for ES2 fallback
 | |
|       EGL_SURFACE_TYPE,
 | |
|       EGL_PBUFFER_BIT,
 | |
|       EGL_BUFFER_SIZE,
 | |
|       32,
 | |
|       EGL_RED_SIZE,
 | |
|       8,
 | |
|       EGL_GREEN_SIZE,
 | |
|       8,
 | |
|       EGL_BLUE_SIZE,
 | |
|       8,
 | |
|       EGL_ALPHA_SIZE,
 | |
|       8,
 | |
|       EGL_DEPTH_SIZE,
 | |
|       0,
 | |
|       EGL_STENCIL_SIZE,
 | |
|       0,
 | |
|       EGL_SAMPLE_BUFFERS,
 | |
|       0,
 | |
|       EGL_NONE};
 | |
| 
 | |
|   EGLConfig config = nullptr;
 | |
|   if (eglChooseConfig(egl_display, configAttrs, &config, 1, &numConfigs) !=
 | |
|       EGL_TRUE) {
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   EGLSurface surface = EGL_NO_SURFACE;
 | |
|   EGLint surfAttrs[] = {EGL_WIDTH,
 | |
|                         width,
 | |
|                         EGL_HEIGHT,
 | |
|                         height,
 | |
|                         EGL_TEXTURE_TARGET,
 | |
|                         EGL_TEXTURE_2D,
 | |
|                         EGL_TEXTURE_FORMAT,
 | |
|                         EGL_TEXTURE_RGBA,
 | |
|                         EGL_NONE};
 | |
| 
 | |
|   surface = eglCreatePbufferFromClientBuffer(egl_display, EGL_D3D_TEXTURE_ANGLE,
 | |
|                                              texture, config, surfAttrs);
 | |
|   if (surface == EGL_NO_SURFACE) {
 | |
|     // fallback to ES2 - it could be that we're running on older hardware
 | |
|     // and ES3 isn't available
 | |
| 
 | |
|     // EGL_RENDERABLE_TYPE is the bit at configAttrs[0]
 | |
|     configAttrs[1] = EGL_OPENGL_ES2_BIT;
 | |
|     config = nullptr;
 | |
|     if (eglChooseConfig(egl_display, configAttrs, &config, 1, &numConfigs) ==
 | |
|         EGL_TRUE) {
 | |
|       surface = eglCreatePbufferFromClientBuffer(
 | |
|           egl_display, EGL_D3D_TEXTURE_ANGLE, texture, config, surfAttrs);
 | |
|     }
 | |
| 
 | |
|     // still no surface? we're done
 | |
|     if (surface == EGL_NO_SURFACE) {
 | |
|       return nullptr;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   dxgi_image->SetSurface(surface, texture_id);
 | |
| 
 | |
|   surfaceMap_[share_handle] = image;
 | |
| 
 | |
|   EGLSurface drawSurface = eglGetCurrentSurface(EGL_DRAW);
 | |
|   EGLSurface readSurface = eglGetCurrentSurface(EGL_READ);
 | |
| 
 | |
|   eglMakeCurrent(egl_display, surface, surface, curContext);
 | |
| 
 | |
|   if (eglBindTexImage(egl_display, surface, EGL_BACK_BUFFER)) {
 | |
|     if (tex_man) {
 | |
|       TextureRef* texture_ref = tex_man->GetTexture(texture_id);
 | |
|       tex_man->SetLevelInfo(texture_ref, GL_TEXTURE_2D, 0, GL_BGRA_EXT, width,
 | |
|                             height, 1, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE,
 | |
|                             gfx::Rect(size));
 | |
|       tex_man->SetLevelImage(texture_ref, GL_TEXTURE_2D, 0, image.get(),
 | |
|                              Texture::BOUND);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   eglMakeCurrent(egl_display, drawSurface, readSurface, curContext);
 | |
| 
 | |
| #endif  // BUILDFLAG(IS_WIN)
 | |
| 
 | |
|   return share_handle;
 | |
| }
 | |
| 
 | |
| void ExternalTextureManager::LockTexture(void* handle) {
 | |
| #if BUILDFLAG(IS_WIN)
 | |
|   auto const img = surfaceMap_.find(handle);
 | |
|   if (img != surfaceMap_.end()) {
 | |
|     GLImageDXGISharedHandle* dxgi_image =
 | |
|         reinterpret_cast<GLImageDXGISharedHandle*>(img->second.get());
 | |
|     dxgi_image->Lock();
 | |
|   }
 | |
| #endif  // BUILDFLAG(IS_WIN)
 | |
| }
 | |
| 
 | |
| void ExternalTextureManager::UnlockTexture(void* handle) {
 | |
| #if BUILDFLAG(IS_WIN)
 | |
|   auto const img = surfaceMap_.find(handle);
 | |
|   if (img != surfaceMap_.end()) {
 | |
|     GLImageDXGISharedHandle* dxgi_image =
 | |
|         reinterpret_cast<GLImageDXGISharedHandle*>(img->second.get());
 | |
|     dxgi_image->Unlock();
 | |
|   }
 | |
| #endif  // BUILDFLAG(IS_WIN)
 | |
| }
 | |
| 
 | |
| void ExternalTextureManager::DeleteTexture(void* handle,
 | |
|                                            TextureManager* tex_man) {
 | |
| #if BUILDFLAG(IS_WIN)
 | |
|   EGLDisplay egl_display = gl::GLSurfaceEGL::GetHardwareDisplay();
 | |
|   if (egl_display == EGL_NO_DISPLAY) {
 | |
|     return;
 | |
|   }
 | |
|   auto const img = surfaceMap_.find(handle);
 | |
|   if (img == surfaceMap_.end()) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   EGLSurface surface = EGL_NO_SURFACE;
 | |
|   GLuint texture_id = 0;
 | |
| 
 | |
|   GLImageDXGISharedHandle* dxgi_image =
 | |
|       reinterpret_cast<GLImageDXGISharedHandle*>(img->second.get());
 | |
|   surface = dxgi_image->surface();
 | |
|   texture_id = dxgi_image->texture_id();
 | |
| 
 | |
|   if (surface != EGL_NO_SURFACE) {
 | |
|     EGLContext curContext = eglGetCurrentContext();
 | |
|     if (curContext != EGL_NO_CONTEXT) {
 | |
|       EGLSurface drawSurface = eglGetCurrentSurface(EGL_DRAW);
 | |
|       EGLSurface readSurface = eglGetCurrentSurface(EGL_READ);
 | |
| 
 | |
|       eglMakeCurrent(egl_display, surface, surface, curContext);
 | |
| 
 | |
|       TextureRef* texture_ref = nullptr;
 | |
|       if (tex_man) {
 | |
|         texture_ref = tex_man->GetTexture(texture_id);
 | |
|       }
 | |
| 
 | |
|       eglReleaseTexImage(egl_display, surface, EGL_BACK_BUFFER);
 | |
| 
 | |
|       if (tex_man && texture_ref) {
 | |
|         tex_man->SetLevelInfo(texture_ref, GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 1,
 | |
|                               0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect());
 | |
|         tex_man->SetLevelImage(texture_ref, GL_TEXTURE_2D, 0, nullptr,
 | |
|                                Texture::UNBOUND);
 | |
|       }
 | |
| 
 | |
|       eglMakeCurrent(egl_display, drawSurface, readSurface, curContext);
 | |
| 
 | |
|       eglDestroySurface(egl_display, surface);
 | |
|     }
 | |
|   }
 | |
|   surfaceMap_.erase(img);
 | |
| #endif  // BUILDFLAG(IS_WIN)
 | |
| }
 | |
| 
 | |
| }  // namespace gles2
 | |
| }  // namespace gpu
 |