Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Windows: Add Direct3D texture interoperability support #26840

Merged
merged 7 commits into from
Apr 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -2227,8 +2227,11 @@ FILE: ../../../flutter/shell/platform/windows/dpi_utils_win32.h
FILE: ../../../flutter/shell/platform/windows/dpi_utils_win32_unittests.cc
FILE: ../../../flutter/shell/platform/windows/event_watcher_win32.cc
FILE: ../../../flutter/shell/platform/windows/event_watcher_win32.h
FILE: ../../../flutter/shell/platform/windows/external_texture_gl.cc
FILE: ../../../flutter/shell/platform/windows/external_texture_gl.h
FILE: ../../../flutter/shell/platform/windows/external_texture.h
FILE: ../../../flutter/shell/platform/windows/external_texture_d3d.cc
FILE: ../../../flutter/shell/platform/windows/external_texture_d3d.h
FILE: ../../../flutter/shell/platform/windows/external_texture_pixelbuffer.cc
FILE: ../../../flutter/shell/platform/windows/external_texture_pixelbuffer.h
FILE: ../../../flutter/shell/platform/windows/flutter_key_map.cc
FILE: ../../../flutter/shell/platform/windows/flutter_platform_node_delegate_win32.cc
FILE: ../../../flutter/shell/platform/windows/flutter_platform_node_delegate_win32.h
Expand Down
30 changes: 21 additions & 9 deletions shell/platform/common/client_wrapper/core_implementations.cc
Original file line number Diff line number Diff line change
Expand Up @@ -157,25 +157,37 @@ TextureRegistrarImpl::TextureRegistrarImpl(
TextureRegistrarImpl::~TextureRegistrarImpl() = default;

int64_t TextureRegistrarImpl::RegisterTexture(TextureVariant* texture) {
FlutterDesktopTextureInfo info = {};
if (auto pixel_buffer_texture = std::get_if<PixelBufferTexture>(texture)) {
FlutterDesktopTextureInfo info = {};
info.type = kFlutterDesktopPixelBufferTexture;
info.pixel_buffer_config.user_data = pixel_buffer_texture;
info.pixel_buffer_config.callback =
[](size_t width, size_t height,
void* user_data) -> const FlutterDesktopPixelBuffer* {
auto texture = static_cast<PixelBufferTexture*>(user_data);
auto buffer = texture->CopyPixelBuffer(width, height);
return buffer;
return texture->CopyPixelBuffer(width, height);
};

int64_t texture_id = FlutterDesktopTextureRegistrarRegisterExternalTexture(
texture_registrar_ref_, &info);
return texture_id;
} else if (auto gpu_surface_texture =
std::get_if<GpuSurfaceTexture>(texture)) {
info.type = kFlutterDesktopGpuSurfaceTexture;
info.gpu_surface_config.struct_size =
sizeof(FlutterDesktopGpuSurfaceTextureConfig);
info.gpu_surface_config.type = gpu_surface_texture->surface_type();
info.gpu_surface_config.user_data = gpu_surface_texture;
info.gpu_surface_config.callback =
[](size_t width, size_t height,
void* user_data) -> const FlutterDesktopGpuSurfaceDescriptor* {
auto texture = static_cast<GpuSurfaceTexture*>(user_data);
return texture->ObtainDescriptor(width, height);
};
} else {
std::cerr << "Attempting to register unknown texture variant." << std::endl;
return -1;
}

std::cerr << "Attempting to register unknown texture variant." << std::endl;
return -1;
int64_t texture_id = FlutterDesktopTextureRegistrarRegisterExternalTexture(
texture_registrar_ref_, &info);
return texture_id;
} // namespace flutter

bool TextureRegistrarImpl::MarkTextureFrameAvailable(int64_t texture_id) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,40 @@ class PixelBufferTexture {
const CopyBufferCallback copy_buffer_callback_;
};

// A GPU surface-based texture.
class GpuSurfaceTexture {
public:
// A callback used for retrieving surface descriptors.
typedef std::function<
const FlutterDesktopGpuSurfaceDescriptor*(size_t width, size_t height)>
ObtainDescriptorCallback;

GpuSurfaceTexture(FlutterDesktopGpuSurfaceType surface_type,
ObtainDescriptorCallback obtain_descriptor_callback)
: surface_type_(surface_type),
obtain_descriptor_callback_(obtain_descriptor_callback) {}

// Returns the callback-provided FlutterDesktopGpuSurfaceDescriptor that
// contains the surface handle. The intended surface size is specified by
// |width| and |height|.
const FlutterDesktopGpuSurfaceDescriptor* ObtainDescriptor(
size_t width,
size_t height) const {
return obtain_descriptor_callback_(width, height);
}

// Gets the surface type.
FlutterDesktopGpuSurfaceType surface_type() const { return surface_type_; }

private:
const FlutterDesktopGpuSurfaceType surface_type_;
const ObtainDescriptorCallback obtain_descriptor_callback_;
};

// The available texture variants.
// Only PixelBufferTexture is currently implemented.
// Other variants are expected to be added in the future.
typedef std::variant<PixelBufferTexture> TextureVariant;
typedef std::variant<PixelBufferTexture, GpuSurfaceTexture> TextureVariant;

// An object keeping track of external textures.
//
Expand Down
93 changes: 90 additions & 3 deletions shell/platform/common/public/flutter_texture_registrar.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,35 @@ typedef struct FlutterDesktopTextureRegistrar*
// Additional types may be added in the future.
typedef enum {
// A Pixel buffer-based texture.
kFlutterDesktopPixelBufferTexture
kFlutterDesktopPixelBufferTexture,
// A platform-specific GPU surface-backed texture.
kFlutterDesktopGpuSurfaceTexture
} FlutterDesktopTextureType;

// Supported GPU surface types.
typedef enum {
// Uninitialized.
kFlutterDesktopGpuSurfaceTypeNone,
// A DXGI shared texture handle (Windows only).
// See
// https://docs.microsoft.com/en-us/windows/win32/api/dxgi/nf-dxgi-idxgiresource-getsharedhandle
kFlutterDesktopGpuSurfaceTypeDxgiSharedHandle,
// A |ID3D11Texture2D| (Windows only).
kFlutterDesktopGpuSurfaceTypeD3d11Texture2D
} FlutterDesktopGpuSurfaceType;

// Supported pixel formats.
typedef enum {
// Uninitialized.
kFlutterDesktopPixelFormatNone,
// Represents a 32-bit RGBA color format with 8 bits each for red, green, blue
// and alpha.
kFlutterDesktopPixelFormatRGBA8888,
// Represents a 32-bit BGRA color format with 8 bits each for blue, green, red
// and alpha.
kFlutterDesktopPixelFormatBGRA8888
} FlutterDesktopPixelFormat;

// An image buffer object.
typedef struct {
// The pixel data buffer.
Expand All @@ -40,20 +66,66 @@ typedef struct {
void* release_context;
} FlutterDesktopPixelBuffer;

// A GPU surface descriptor.
typedef struct {
// The size of this struct. Must be
// sizeof(FlutterDesktopGpuSurfaceDescriptor).
size_t struct_size;
// The surface handle. The expected type depends on the
// |FlutterDesktopGpuSurfaceType|.
//
// Provide a |ID3D11Texture2D*| when using
// |kFlutterDesktopGpuSurfaceTypeD3d11Texture2D| or a |HANDLE| when using
// |kFlutterDesktopGpuSurfaceTypeDxgiSharedHandle|.
//
// The referenced resource needs to stay valid until it has been opened by
// Flutter. Consider incrementing the resource's reference count in the
// |FlutterDesktopGpuSurfaceTextureCallback| and registering a
// |release_callback| for decrementing the reference count once it has been
// opened.
void* handle;
// The physical width.
size_t width;
// The physical height.
size_t height;
// The visible width.
// It might be less or equal to the physical |width|.
size_t visible_width;
// The visible height.
// It might be less or equal to the physical |height|.
size_t visible_height;
// The pixel format which might be optional depending on the surface type.
FlutterDesktopPixelFormat format;
// An optional callback that gets invoked when the |handle| has been opened.
void (*release_callback)(void* release_context);
// Opaque data passed to |release_callback|.
void* release_context;
} FlutterDesktopGpuSurfaceDescriptor;

// The pixel buffer copy callback definition provided to
// the Flutter engine to copy the texture.
// It is invoked with the intended surface size specified by |width| and
// |height| and the |user_data| held by FlutterDesktopPixelBufferTextureConfig.
// |height| and the |user_data| held by
// |FlutterDesktopPixelBufferTextureConfig|.
//
// As this is usually called from the render thread, the callee must take
// care of proper synchronization. It also needs to be ensured that the
// returned FlutterDesktopPixelBuffer isn't released prior to unregistering
// returned |FlutterDesktopPixelBuffer| isn't released prior to unregistering
// the corresponding texture.
typedef const FlutterDesktopPixelBuffer* (
*FlutterDesktopPixelBufferTextureCallback)(size_t width,
size_t height,
void* user_data);

// The GPU surface callback definition provided to the Flutter engine to obtain
// the surface. It is invoked with the intended surface size specified by
// |width| and |height| and the |user_data| held by
// |FlutterDesktopGpuSurfaceTextureConfig|.
typedef const FlutterDesktopGpuSurfaceDescriptor* (
*FlutterDesktopGpuSurfaceTextureCallback)(size_t width,
size_t height,
void* user_data);

// An object used to configure pixel buffer textures.
typedef struct {
// The callback used by the engine to copy the pixel buffer object.
Expand All @@ -62,10 +134,25 @@ typedef struct {
void* user_data;
} FlutterDesktopPixelBufferTextureConfig;

// An object used to configure GPU-surface textures.
typedef struct {
// The size of this struct. Must be
// sizeof(FlutterDesktopGpuSurfaceTextureConfig).
size_t struct_size;
// The concrete surface type (e.g.
// |kFlutterDesktopGpuSurfaceTypeDxgiSharedHandle|)
FlutterDesktopGpuSurfaceType type;
// The callback used by the engine to obtain the surface descriptor.
FlutterDesktopGpuSurfaceTextureCallback callback;
// Opaque data that will get passed to the provided |callback|.
void* user_data;
} FlutterDesktopGpuSurfaceTextureConfig;

typedef struct {
FlutterDesktopTextureType type;
union {
FlutterDesktopPixelBufferTextureConfig pixel_buffer_config;
FlutterDesktopGpuSurfaceTextureConfig gpu_surface_config;
};
} FlutterDesktopTextureInfo;

Expand Down
7 changes: 5 additions & 2 deletions shell/platform/windows/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,11 @@ source_set("flutter_windows_source") {
"dpi_utils_win32.h",
"event_watcher_win32.cc",
"event_watcher_win32.h",
"external_texture_gl.cc",
"external_texture_gl.h",
"external_texture.h",
"external_texture_d3d.cc",
"external_texture_d3d.h",
"external_texture_pixelbuffer.cc",
"external_texture_pixelbuffer.h",
"flutter_key_map.cc",
"flutter_platform_node_delegate_win32.cc",
"flutter_platform_node_delegate_win32.h",
Expand Down
43 changes: 43 additions & 0 deletions shell/platform/windows/angle_surface_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,9 @@ bool AngleSurfaceManager::Initialize() {
void AngleSurfaceManager::CleanUp() {
EGLBoolean result = EGL_FALSE;

// Needs to be reset before destroying the EGLContext.
resolved_device_.Reset();

if (egl_display_ != EGL_NO_DISPLAY && egl_context_ != EGL_NO_CONTEXT) {
result = eglDestroyContext(egl_display_, egl_context_);
egl_context_ = EGL_NO_CONTEXT;
Expand Down Expand Up @@ -288,4 +291,44 @@ EGLBoolean AngleSurfaceManager::SwapBuffers() {
return (eglSwapBuffers(egl_display_, render_surface_));
}

EGLSurface AngleSurfaceManager::CreateSurfaceFromHandle(
EGLenum handle_type,
EGLClientBuffer handle,
const EGLint* attributes) const {
return eglCreatePbufferFromClientBuffer(egl_display_, handle_type, handle,
egl_config_, attributes);
}

bool AngleSurfaceManager::GetDevice(ID3D11Device** device) {
using Microsoft::WRL::ComPtr;

if (!resolved_device_) {
PFNEGLQUERYDISPLAYATTRIBEXTPROC egl_query_display_attrib_EXT =
reinterpret_cast<PFNEGLQUERYDISPLAYATTRIBEXTPROC>(
eglGetProcAddress("eglQueryDisplayAttribEXT"));

PFNEGLQUERYDEVICEATTRIBEXTPROC egl_query_device_attrib_EXT =
reinterpret_cast<PFNEGLQUERYDEVICEATTRIBEXTPROC>(
eglGetProcAddress("eglQueryDeviceAttribEXT"));

if (!egl_query_display_attrib_EXT || !egl_query_device_attrib_EXT) {
return false;
}

EGLAttrib egl_device = 0;
EGLAttrib angle_device = 0;
if (egl_query_display_attrib_EXT(egl_display_, EGL_DEVICE_EXT,
&egl_device) == EGL_TRUE) {
if (egl_query_device_attrib_EXT(
reinterpret_cast<EGLDeviceEXT>(egl_device),
EGL_D3D11_DEVICE_ANGLE, &angle_device) == EGL_TRUE) {
resolved_device_ = reinterpret_cast<ID3D11Device*>(angle_device);
}
}
}

resolved_device_.CopyTo(device);
return (resolved_device_ != nullptr);
}

} // namespace flutter
21 changes: 18 additions & 3 deletions shell/platform/windows/angle_surface_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
#include <GLES2/gl2ext.h>

// Windows platform specific includes
#include <d3d11.h>
#include <windows.h>
#include <wrl/client.h>
#include <memory>

#include "window_binding_handler.h"
Expand Down Expand Up @@ -69,15 +71,25 @@ class AngleSurfaceManager {
// not null.
EGLBoolean SwapBuffers();

private:
bool Initialize();
void CleanUp();
// Creates a |EGLSurface| from the provided handle.
EGLSurface CreateSurfaceFromHandle(EGLenum handle_type,
EGLClientBuffer handle,
const EGLint* attributes) const;

// Gets the |EGLDisplay|.
EGLDisplay egl_display() const { return egl_display_; };

// Gets the |ID3D11Device| chosen by ANGLE.
bool GetDevice(ID3D11Device** device);

private:
// Creates a new surface manager retaining reference to the passed-in target
// for the lifetime of the manager.
AngleSurfaceManager();

bool Initialize();
void CleanUp();

// Attempts to initialize EGL using ANGLE.
bool InitializeEGL(
PFNEGLGETPLATFORMDISPLAYEXTPROC egl_get_platform_display_EXT,
Expand Down Expand Up @@ -108,6 +120,9 @@ class AngleSurfaceManager {
EGLint surface_width_ = 0;
EGLint surface_height_ = 0;

// The current D3D device.
Microsoft::WRL::ComPtr<ID3D11Device> resolved_device_;

// Number of active instances of AngleSurfaceManager
static int instance_count_;
};
Expand Down
Loading