blob: 08b1cc752ae9802c6ea0d178d9accca39f5a7992 [file] [log] [blame]
// Copyright 2019 The Chromium 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 "ui/gl/gl_image_dxgi_swap_chain.h"
#include "ui/gl/egl_util.h"
#include "ui/gl/gl_bindings.h"
#ifndef EGL_ANGLE_d3d_texture_client_buffer
#define EGL_ANGLE_d3d_texture_client_buffer 1
#define EGL_D3D_TEXTURE_ANGLE 0x33A3
#endif /* EGL_ANGLE_d3d_texture_client_buffer */
namespace gl {
namespace {
bool SwapChainSupportedBindFormat(gfx::BufferFormat format) {
switch (format) {
case gfx::BufferFormat::RGBA_8888:
case gfx::BufferFormat::RGBX_8888:
case gfx::BufferFormat::RGBA_F16:
return true;
default:
return false;
};
}
bool SwapChainHasAlpha(gfx::BufferFormat format) {
DCHECK(SwapChainSupportedBindFormat(format));
switch (format) {
case gfx::BufferFormat::RGBA_8888:
case gfx::BufferFormat::RGBA_F16:
return true;
case gfx::BufferFormat::RGBX_8888:
return false;
default:
NOTREACHED();
return false;
};
}
EGLConfig ChooseCompatibleConfig(gfx::BufferFormat format, EGLDisplay display) {
DCHECK(SwapChainSupportedBindFormat(format));
const EGLint color_bits = format == gfx::BufferFormat::RGBA_F16 ? 16 : 8;
const EGLint buffer_bind_to_texture = SwapChainHasAlpha(format)
? EGL_BIND_TO_TEXTURE_RGBA
: EGL_BIND_TO_TEXTURE_RGB;
const EGLint buffer_size =
color_bits * 3 + (SwapChainHasAlpha(format) ? color_bits : 0);
std::vector<EGLint> attrib_list = {
EGL_RED_SIZE, color_bits, EGL_GREEN_SIZE, color_bits,
EGL_BLUE_SIZE, color_bits, EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
buffer_bind_to_texture, EGL_TRUE, EGL_BUFFER_SIZE, buffer_size};
// It is assumed that EGL_EXT_pixel_format_float extension is supported by
// ANGLE.
if (format == gfx::BufferFormat::RGBA_F16) {
attrib_list.push_back(EGL_COLOR_COMPONENT_TYPE_EXT);
attrib_list.push_back(EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT);
}
attrib_list.push_back(EGL_NONE);
EGLint num_config = 0;
EGLBoolean result =
eglChooseConfig(display, attrib_list.data(), nullptr, 0, &num_config);
if (result != EGL_TRUE)
return nullptr;
std::vector<EGLConfig> all_configs(num_config);
result = eglChooseConfig(display, attrib_list.data(), all_configs.data(),
num_config, &num_config);
if (result != EGL_TRUE)
return nullptr;
for (EGLConfig config : all_configs) {
EGLint bits = 0;
// Ensures that the config chosen has requested number of bits.
if (!eglGetConfigAttrib(display, config, EGL_RED_SIZE, &bits) ||
bits != color_bits) {
continue;
}
if (!eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &bits) ||
bits != color_bits) {
continue;
}
if (!eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &bits) ||
bits != color_bits) {
continue;
}
if (SwapChainHasAlpha(format) &&
(!eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &bits) ||
bits != color_bits)) {
continue;
}
return config;
}
return nullptr;
}
EGLSurface CreatePbuffer(const Microsoft::WRL::ComPtr<ID3D11Texture2D>& texture,
gfx::BufferFormat format,
EGLConfig config,
EGLDisplay display,
unsigned target) {
DCHECK(SwapChainSupportedBindFormat(format));
D3D11_TEXTURE2D_DESC desc;
texture->GetDesc(&desc);
EGLint width = desc.Width;
EGLint height = desc.Height;
EGLint pBufferAttributes[] = {
EGL_WIDTH,
width,
EGL_HEIGHT,
height,
EGL_TEXTURE_TARGET,
EGL_TEXTURE_2D,
EGL_TEXTURE_FORMAT,
SwapChainHasAlpha(format) ? EGL_TEXTURE_RGBA : EGL_TEXTURE_RGB,
EGL_NONE};
return eglCreatePbufferFromClientBuffer(
display, EGL_D3D_TEXTURE_ANGLE, texture.Get(), config, pBufferAttributes);
}
} // anonymous namespace
GLImageDXGISwapChain::GLImageDXGISwapChain(
const gfx::Size& size,
gfx::BufferFormat buffer_format,
Microsoft::WRL::ComPtr<ID3D11Texture2D> texture,
Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain)
: size_(size),
buffer_format_(buffer_format),
texture_(texture),
swap_chain_(swap_chain),
display_(eglGetCurrentDisplay()),
config_(ChooseCompatibleConfig(buffer_format, display_)) {
DCHECK(texture_);
DCHECK(swap_chain_);
DCHECK(config_);
}
GLImage::BindOrCopy GLImageDXGISwapChain::ShouldBindOrCopy() {
return BIND;
}
bool GLImageDXGISwapChain::BindTexImage(unsigned target) {
DestroySurface();
DCHECK(texture_);
DCHECK_EQ(surface_, EGL_NO_SURFACE);
DCHECK(config_);
surface_ = CreatePbuffer(texture_, buffer_format_, config_, display_, target);
if (surface_ == EGL_NO_SURFACE) {
DLOG(ERROR) << "eglCreatePbufferSurface failed with error "
<< ui::GetLastEGLErrorString();
return false;
}
return eglBindTexImage(display_, surface_, EGL_BACK_BUFFER) == EGL_TRUE;
}
void GLImageDXGISwapChain::ReleaseTexImage(unsigned target) {}
bool GLImageDXGISwapChain::CopyTexImage(unsigned target) {
return false;
}
bool GLImageDXGISwapChain::CopyTexSubImage(unsigned target,
const gfx::Point& offset,
const gfx::Rect& rect) {
return false;
}
void GLImageDXGISwapChain::Flush() {}
unsigned GLImageDXGISwapChain::GetInternalFormat() {
return SwapChainHasAlpha(buffer_format_) ? GL_RGBA : GL_RGB;
}
gfx::Size GLImageDXGISwapChain::GetSize() {
return size_;
}
void GLImageDXGISwapChain::OnMemoryDump(
base::trace_event::ProcessMemoryDump* pmd,
uint64_t process_tracing_id,
const std::string& dump_name) {}
GLImage::Type GLImageDXGISwapChain::GetType() const {
return Type::DXGI_SWAP_CHAIN;
}
bool GLImageDXGISwapChain::ScheduleOverlayPlane(
gfx::AcceleratedWidget widget,
int z_order,
gfx::OverlayTransform transform,
const gfx::Rect& bounds_rect,
const gfx::RectF& crop_rect,
bool enable_blend,
std::unique_ptr<gfx::GpuFence> gpu_fence) {
NOTREACHED();
return false;
}
void GLImageDXGISwapChain::DestroySurface() {
if (surface_ != EGL_NO_SURFACE) {
if (!eglDestroySurface(display_, surface_)) {
DLOG(ERROR) << "eglDestroySurface failed with error "
<< ui::GetLastEGLErrorString();
}
surface_ = EGL_NO_SURFACE;
}
}
GLImageDXGISwapChain::~GLImageDXGISwapChain() {
DestroySurface();
}
} // namespace gl