diff --git a/build_variables.bzl b/build_variables.bzl index 73f196c86..b567c66e8 100644 --- a/build_variables.bzl +++ b/build_variables.bzl @@ -1,6 +1,7 @@ """ Common build configuration definitions. """ + GFXSTREAM_COMMON_COPTS = [ "-Wall", "-Wextra", @@ -26,6 +27,7 @@ GFXSTREAM_COMMON_COPTS = [ ], "//conditions:default": [], }) + GFXSTREAM_HOST_COPTS = GFXSTREAM_COMMON_COPTS + [ ] + select({ "@platforms//os:windows": [ @@ -35,6 +37,7 @@ GFXSTREAM_HOST_COPTS = GFXSTREAM_COMMON_COPTS + [ "-fno-exceptions", ], }) + GFXSTREAM_HOST_VK_DEFINES = [ "VK_GFXSTREAM_STRUCTURE_TYPE_EXT", "VK_GOOGLE_gfxstream", @@ -51,6 +54,7 @@ GFXSTREAM_HOST_VK_DEFINES = [ ], "//conditions:default": [], }) + GFXSTREAM_HOST_DEFINES = GFXSTREAM_HOST_VK_DEFINES + [ "BUILDING_EMUGL_COMMON_SHARED", "EMUGL_BUILD", @@ -78,3 +82,12 @@ GFXSTREAM_HOST_DEFINES = GFXSTREAM_HOST_VK_DEFINES + [ ], "//conditions:default": [], }) + +GFXSTREAM_HOST_LINKOPTS = select({ + "@platforms//os:linux": [ + "-Wl,--warn-backrefs", + "-Wl,--warn-backrefs-exclude=*llvm*", + "-Wl,--fatal-warnings", + ], + "//conditions:default": [], +}) diff --git a/host/Android.bp b/host/Android.bp index 22ace077b..2a4a3595d 100644 --- a/host/Android.bp +++ b/host/Android.bp @@ -45,16 +45,17 @@ cc_library_host_static { gfxstream_backend_static_deps = [ "libgfxstream_common_base", + "libgfxstream_common_logging", "libgfxstream_common_utils", "libgfxstream_etc", "libgfxstream_glestranslator_egl", "libgfxstream_glestranslator_glescm", "libgfxstream_glestranslator_glesv2", "libgfxstream_host_address_space", - "libgfxstream_host_compressedtextures", - "libgfxstream_host_decoder_common", "libgfxstream_host_common", "libgfxstream_host_compressedtextures", + "libgfxstream_host_compressedtextures", + "libgfxstream_host_decoder_common", "libgfxstream_host_features", "libgfxstream_host_gl_server", "libgfxstream_host_gles1_dec", @@ -63,11 +64,10 @@ gfxstream_backend_static_deps = [ "libgfxstream_host_glsnapshot", "libgfxstream_host_iostream", "libgfxstream_host_library", - "libgfxstream_common_logging", + "libgfxstream_host_native_window", "libgfxstream_host_openglesdispatch", "libgfxstream_host_rendercontrol_dec", "libgfxstream_host_renderdoc", - "libgfxstream_host_snapshot", "libgfxstream_host_tracing", "libgfxstream_host_vulkan_cereal", "libgfxstream_host_vulkan_emulatedtextures", @@ -115,11 +115,12 @@ cc_defaults { "libgfxstream_host_decoder_common", "libgfxstream_host_features", "libgfxstream_host_renderdoc", - "libgfxstream_host_snapshot", "libgfxstream_host_tracing", "libgfxstream_host_gles2_dec", "libgfxstream_host_glsnapshot", + "libgfxstream_host_address_space", "libgfxstream_host_vulkan_cereal", + "libgfxstream_host_native_window", ], shared_libs: [ "liblog", // gfxstream_base uses this via perfetto-libperfettobase @@ -132,9 +133,6 @@ cc_defaults { "channel_stream.cpp", "color_buffer.cpp", "frame_buffer.cpp", - "hwc2.cpp", - "post_worker.cpp", - "post_worker_gl.cpp", "read_buffer.cpp", "render_api.cpp", "render_channel_impl.cpp", @@ -160,12 +158,10 @@ cc_defaults { ], target: { host: { - srcs: ["native_sub_window_x11.cpp"], static_libs: gfxstream_backend_snapshot_static_deps, whole_static_libs: gfxstream_backend_snapshot_static_deps, }, android: { - srcs: ["native_sub_window_android.cpp"], shared_libs: [ "libnativewindow", ], @@ -198,9 +194,9 @@ cc_test_host { "libgfxstream_common_image", "libgfxstream_common_logging", "libgfxstream_common_testenv", - "libgfxstream_host_snapshot", "libgfxstream_host_test_support", "libgfxstream_host_vulkan_server", + "libgfxstream_host_address_space", "libgfxstream_oswindow_test_support", "libgmock", ], diff --git a/host/BUILD.bazel b/host/BUILD.bazel index 8ce64ed75..16cd20819 100644 --- a/host/BUILD.bazel +++ b/host/BUILD.bazel @@ -1,7 +1,7 @@ load("@protobuf//bazel:cc_proto_library.bzl", "cc_proto_library") load("@protobuf//bazel:proto_library.bzl", "proto_library") -load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test", "objc_library") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -56,86 +56,23 @@ cc_library( defines = GFXSTREAM_HOST_DEFINES, features = ["-parse_headers"], includes = ["include"], + linkopts = GFXSTREAM_HOST_LINKOPTS, visibility = ["//visibility:public"], deps = [ "//host/features:gfxstream_host_features", ], ) -cc_library( - name = "gfxstream_host_headers", - hdrs = [ - "buffer.h", - "color_buffer.h", - "compositor.h", - "frame_buffer.h", - "framework_formats.h", - "gles_compat.h", - "handle.h", - "hwc2.h", - "native_sub_window.h", - "post_commands.h", - "post_worker.h", - "readback_worker.h", - "stale_ptr_registry.h", - "vsync_thread.h", - ], - copts = GFXSTREAM_HOST_COPTS, - defines = GFXSTREAM_HOST_DEFINES, - includes = ["."], - deps = [ - ":gfxstream_backend_headers", - "//common/base:gfxstream_common_base", - "//common/logging:gfxstream_common_logging", - "//host/common:gfxstream_host_common", - "//host/features:gfxstream_host_features", - "//host/snapshot:gfxstream_host_snapshot", - "//third_party/opengl:gfxstream_egl_headers", - "//third_party/opengl:gfxstream_gles2_headers", - "//third_party/opengl:gfxstream_gles3_headers", - "//third_party/vulkan:gfxstream_vulkan_headers", - "//third_party/xcb", - ], -) - -objc_library( - name = "gfxstream_backend_static-darwin", - srcs = [ - "gles_compat.h", - "native_sub_window.h", - "native_sub_window_cocoa.mm", - ], - copts = GFXSTREAM_HOST_COPTS + [ - "-Wno-deprecated-declarations", - # These sources use manual reference counting, so disable ARC which - # objc_library enables by default. - "-fno-objc-arc", - ], - defines = GFXSTREAM_HOST_DEFINES, - sdk_frameworks = [ - "AppKit", - "QuartzCore", - "IOSurface", - ], - target_compatible_with = [ - "@platforms//os:macos", - ], - deps = [ - ":gfxstream_backend_headers", - "//third_party/opengl:gfxstream_egl_headers", - ], -) - cc_library( name = "gfxstream_backend_static", srcs = [ "buffer.cpp", + "buffer.h", "channel_stream.cpp", + "channel_stream.h", "color_buffer.cpp", + "color_buffer.h", "frame_buffer.cpp", - "hwc2.cpp", - "post_worker.cpp", - "post_worker_gl.cpp", "read_buffer.cpp", "render_channel_impl.cpp", "render_control.cpp", @@ -153,32 +90,11 @@ cc_library( "virtio_gpu_ring_blob.cpp", "virtio_gpu_timelines.cpp", "vsync_thread.cpp", - ] + select({ - "@platforms//os:macos": [], - "@platforms//os:windows": [ - "native_sub_window_win32.cpp", - ], - "@platforms//os:linux": [ - "native_sub_window_x11.cpp", - ], - "//conditions:default": [], - }), + ], hdrs = [ - "buffer.h", - "channel_stream.h", "color_buffer.h", - "compositor.h", "frame_buffer.h", - "framework_formats.h", - "gles_compat.h", - "handle.h", - "hwc2.h", - "native_sub_window.h", - "post_commands.h", - "post_worker.h", - "post_worker_gl.h", "read_buffer.h", - "readback_worker.h", "render_channel_impl.h", "render_control.h", "render_lib_impl.h", @@ -187,7 +103,6 @@ cc_library( "render_window.h", "renderer_impl.h", "ring_stream.h", - "stale_ptr_registry.h", "sync_thread.h", "virtgpu_gfxstream_protocol.h", "virtio_gpu.h", @@ -208,14 +123,13 @@ cc_library( defines = GFXSTREAM_HOST_DEFINES + ["QEMU_NEXT"], includes = [ ".", - "gl", ], + linkopts = GFXSTREAM_HOST_LINKOPTS, linkstatic = True, visibility = ["//visibility:public"], deps = [ ":gfxstream_backend_cc_proto", ":gfxstream_backend_headers", - ":gfxstream_host_headers", "//common/base:gfxstream_common_base", "//common/logging:gfxstream_common_logging", "//host/address_space:gfxstream_host_address_space", @@ -233,9 +147,9 @@ cc_library( "//host/gl/glestranslator/gles_cm:gles_cm_translator_static", "//host/iostream:gfxstream_host_iostream", "//host/library:gfxstream_host_library", + "//host/native_window:gfxstream_host_native_window", "//host/renderControl_dec", "//host/renderdoc:gfxstream_host_renderdoc", - "//host/snapshot:gfxstream_host_snapshot", "//host/tracing:gfxstream_host_tracing", "//host/vulkan:gfxstream_vulkan_server", "//third_party/drm:gfxstream_drm_headers", @@ -246,12 +160,7 @@ cc_library( "//third_party/xcb", "@protobuf", "@protobuf//src/google/protobuf/io", - ] + select({ - "@platforms//os:macos": [ - ":gfxstream_backend_static-darwin", - ], - "//conditions:default": [], - }), + ], ) cc_library( @@ -265,13 +174,13 @@ cc_library( "-Wno-return-type-c-linkage", ], defines = GFXSTREAM_HOST_DEFINES, + linkopts = GFXSTREAM_HOST_LINKOPTS, linkstatic = True, visibility = ["//visibility:public"], deps = [ ":gfxstream_backend_cc_proto", ":gfxstream_backend_headers", ":gfxstream_backend_static", - ":gfxstream_host_headers", "//common/base:gfxstream_common_base", "//common/logging:gfxstream_common_logging", "//common/utils:gfxstream_common_utils", @@ -290,13 +199,13 @@ cc_binary( ], copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, + linkopts = GFXSTREAM_HOST_LINKOPTS, linkshared = True, visibility = ["//visibility:public"], deps = [ ":gfxstream_backend_cc_proto", ":gfxstream_backend_headers", ":gfxstream_backend_static", - ":gfxstream_host_headers", "//common/base:gfxstream_common_base", "//common/logging:gfxstream_common_logging", "//common/utils:gfxstream_common_utils", @@ -313,12 +222,14 @@ cc_test( "frame_buffer_unittest.cpp", ], copts = GFXSTREAM_HOST_COPTS, + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ ":gfxstream_backend_static", "//common/base:gfxstream_common_base", "//common/testenv:graphics_test_environment_support", "//host/common:gfxstream_host_common", "//host/features:gfxstream_host_features", + "//host/gl:gfxstream_opengl_server", "//host/testlibs/oswindow:gfxstream_oswindow_test_support", "//host/testlibs/support:gfxstream_host_testing_support", "@com_google_googletest//:gtest", @@ -332,6 +243,7 @@ cc_test( "vsync_thread_unittest.cpp", ], copts = GFXSTREAM_HOST_COPTS, + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ ":gfxstream_backend_static", "//host/testlibs/support:gfxstream_host_testing_support", diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt index a09365316..6b61ae52d 100644 --- a/host/CMakeLists.txt +++ b/host/CMakeLists.txt @@ -47,11 +47,11 @@ add_subdirectory(common) add_subdirectory(features) add_subdirectory(iostream) add_subdirectory(library) -add_subdirectory(snapshot) add_subdirectory(tracing) add_subdirectory(decoder_common) add_subdirectory(compressed_textures) add_subdirectory(renderdoc) +add_subdirectory(native_window) add_library( gfxstream_backend.headers @@ -62,7 +62,6 @@ target_link_libraries( INTERFACE gfxstream_features.headers gfxstream_host_decoder_common - gfxstream_host_snapshot.headers gfxstream_host_renderdoc ) target_include_directories( @@ -82,9 +81,6 @@ set(stream-server-core-sources channel_stream.cpp color_buffer.cpp frame_buffer.cpp - hwc2.cpp - post_worker.cpp - post_worker_gl.cpp read_buffer.cpp render_channel_impl.cpp render_control.cpp @@ -102,15 +98,7 @@ set(stream-server-core-sources virtio_gpu_ring_blob.cpp virtio_gpu_timelines.cpp vsync_thread.cpp) -if (APPLE) - set(stream-server-core-platform-sources native_sub_window_cocoa.mm) -elseif (WIN32) - set(stream-server-core-platform-sources native_sub_window_win32.cpp) -elseif (QNX) - set(stream-server-core-platform-sources native_sub_window_qnx.cpp) -else() - set(stream-server-core-platform-sources native_sub_window_x11.cpp) -endif() + @@ -120,7 +108,6 @@ add_library( gfxstream_backend_static STATIC ${stream-server-core-sources} - ${stream-server-core-platform-sources} ) target_link_libraries( gfxstream_backend_static @@ -138,7 +125,6 @@ target_link_libraries( gfxstream_host_iostream gfxstream_host_library gfxstream_host_renderdoc - gfxstream_host_snapshot.headers gfxstream_host_tracing gfxstream_opengl_headers gfxstream_openglesdispatch @@ -146,6 +132,7 @@ target_link_libraries( gfxstream-vulkan-server GLES_CM_translator_static renderControl_dec + gfxstream_host_native_window ) if(NOT APPLE AND NOT WIN32) target_link_libraries(gfxstream_backend_static PUBLIC gfxstream_xcb_headers) @@ -358,7 +345,8 @@ endfunction() target_link_libraries( Vulkan_unittests PUBLIC - "-framework AppKit") + "-framework AppKit" + "-framework OpenGL") elseif (QNX) target_compile_definitions(Vulkan_unittests PRIVATE -DVK_USE_PLATFORM_SCREEN_QNX) elseif (UNIX) diff --git a/host/address_space/BUILD.bazel b/host/address_space/BUILD.bazel index 6db554cfb..6b7a9ef48 100644 --- a/host/address_space/BUILD.bazel +++ b/host/address_space/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -17,6 +17,7 @@ cc_library( hdrs = glob(["include/**/*.h"]), copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, + linkopts = GFXSTREAM_HOST_LINKOPTS, strip_include_prefix = "include", deps = [ "//common/base:gfxstream_common_base", @@ -30,6 +31,7 @@ cc_test( srcs = [ "ring_buffer_unittest.cpp", ], + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ ":gfxstream_host_address_space", "//common/base:gfxstream_common_base", diff --git a/host/buffer.h b/host/buffer.h index 59cf6b2c4..bcab55e08 100644 --- a/host/buffer.h +++ b/host/buffer.h @@ -17,9 +17,9 @@ #include #include "gfxstream/host/external_object_manager.h" -#include "handle.h" +#include "gfxstream/host/handle.h" +#include "gfxstream/host/lazy_snapshot_object.h" #include "render-utils/stream.h" -#include "snapshot/LazySnapshotObj.h" namespace gfxstream { namespace host { diff --git a/host/color_buffer.cpp b/host/color_buffer.cpp index e150110de..ac927f93f 100644 --- a/host/color_buffer.cpp +++ b/host/color_buffer.cpp @@ -45,16 +45,11 @@ bool shouldAttemptExternalMemorySharing(GfxstreamFormat format) { class ColorBuffer::Impl : public LazySnapshotObj { public: - static std::unique_ptr create(gl::EmulationGl* emulationGl, - vk::VkEmulation* emulationVk, - uint32_t width, - uint32_t height, - GfxstreamFormat format, - HandleType handle, - gfxstream::Stream* stream = nullptr); - - static std::unique_ptr onLoad(gl::EmulationGl* emulationGl, - vk::VkEmulation* emulationVk, + static std::unique_ptr create(gl::EmulationGl* emulationGl, vk::VkEmulation* emulationVk, + uint32_t width, uint32_t height, GfxstreamFormat format, + HandleType handle, gfxstream::Stream* stream = nullptr); + + static std::unique_ptr onLoad(gl::EmulationGl* emulationGl, vk::VkEmulation* emulationVk, gfxstream::Stream* stream); void onSave(gfxstream::Stream* stream); @@ -77,35 +72,26 @@ class ColorBuffer::Impl : public LazySnapshotObj { const void* pixels, void* metadata = nullptr); bool updateGlFromBytes(const void* bytes, std::size_t bytesSize); - std::unique_ptr borrowForComposition(UsedApi api, bool isTarget); - std::unique_ptr borrowForDisplay(UsedApi api); - bool flushFromGl(); bool flushFromVk(); bool flushFromVkBytes(const void* bytes, size_t bytesSize); bool invalidateForGl(); bool invalidateForVk(); + bool invalidateForBackend(Backend backend); + bool flushFromBackend(Backend backend); + bool importHandle(void* handle, bool preserveContent); std::optional exportBlob(); + gl::ColorBufferGl* getColorBufferGl() const { #if GFXSTREAM_ENABLE_HOST_GLES - bool canUseGlOps(); - bool glOpBlitFromCurrentReadBuffer(); - bool glOpBindToTexture(); - bool glOpBindToTexture2(); - bool glOpBindToRenderbuffer(); - bool glOpReadback(unsigned char* img, bool readbackBgra); - bool glOpReadbackAsync(GLuint buffer, bool readbackBgra); - bool glOpImportEglNativePixmap(void* pixmap, bool preserveContent); - bool glOpSwapYuvTexturesAndUpdate(GLenum format, GLenum type, GfxstreamFormat texturesFormat, - GLuint* textures); - bool glOpIsFastBlitSupported() const; - bool glOpPostLayer(const ComposeLayer& l, int frameWidth, int frameHeight, - const std::optional>& colorTransform); - bool glOpPostViewportScaledWithOverlay( - float rotation, float dx, float dy, float scaleX, float scaleY, - const std::optional>& colorTransform); + return mColorBufferGl.get(); +#else + return nullptr; #endif + } + + vk::ColorBufferVk* getColorBufferVk() const { return mColorBufferVk.get(); } private: Impl(HandleType, uint32_t width, uint32_t height, GfxstreamFormat format); @@ -128,10 +114,7 @@ class ColorBuffer::Impl : public LazySnapshotObj { }; ColorBuffer::Impl::Impl(HandleType handle, uint32_t width, uint32_t height, GfxstreamFormat format) - : mHandle(handle), - mWidth(width), - mHeight(height), - mFormat(format) {} + : mHandle(handle), mWidth(width), mHeight(height), mFormat(format) {} /*static*/ std::unique_ptr ColorBuffer::Impl::create( @@ -183,15 +166,14 @@ std::unique_ptr ColorBuffer::Impl::create( #if GFXSTREAM_ENABLE_HOST_GLES bool vkSnapshotEnabled = emulationVk && emulationVk->getFeatures().VulkanSnapshots.enabled(); - if ((!stream || vkSnapshotEnabled) && colorBuffer->mColorBufferGl && colorBuffer->mColorBufferVk && - shouldAttemptExternalMemorySharing(format)) { + if ((!stream || vkSnapshotEnabled) && colorBuffer->mColorBufferGl && + colorBuffer->mColorBufferVk && shouldAttemptExternalMemorySharing(format)) { colorBuffer->touch(); auto memoryExport = emulationVk->exportColorBufferMemory(handle); if (memoryExport) { if (colorBuffer->mColorBufferGl->importMemory( - memoryExport->handleInfo.toManagedDescriptor(), - memoryExport->size, memoryExport->dedicatedAllocation, - memoryExport->linearTiling)) { + memoryExport->handleInfo.toManagedDescriptor(), memoryExport->size, + memoryExport->dedicatedAllocation, memoryExport->linearTiling)) { colorBuffer->mGlAndVkAreSharingExternalMemory = true; } else { GFXSTREAM_ERROR("Failed to import memory to ColorBufferGl:%d", handle); @@ -219,8 +201,8 @@ std::unique_ptr ColorBuffer::Impl::onLoad(gl::EmulationGl* em const auto height = static_cast(stream->getBe32()); const auto format = static_cast(stream->getBe32()); - std::unique_ptr colorBuffer = Impl::create(emulationGl, emulationVk, width, height, - format, handle, stream); + std::unique_ptr colorBuffer = + Impl::create(emulationGl, emulationVk, width, height, format, handle, stream); return colorBuffer; } @@ -251,14 +233,9 @@ void ColorBuffer::Impl::restore() { #endif } -void ColorBuffer::Impl::readToBytes( - int x, - int y, - int width, - int height, - GfxstreamFormat pixelsFormat, - void* outPixels, - uint64_t outPixelsSize) { +void ColorBuffer::Impl::readToBytes(int x, int y, int width, int height, + GfxstreamFormat pixelsFormat, void* outPixels, + uint64_t outPixelsSize) { touch(); #if GFXSTREAM_ENABLE_HOST_GLES @@ -283,14 +260,15 @@ void ColorBuffer::Impl::readToBytesScaled( #if GFXSTREAM_ENABLE_HOST_GLES if (mColorBufferGl) { - mColorBufferGl->readPixelsScaled(pixelsWidth, pixelsHeight, pixelsRotation, - rect, pixelsFormat, outPixels, colorTransform); + mColorBufferGl->readPixelsScaled(pixelsWidth, pixelsHeight, pixelsRotation, rect, + pixelsFormat, outPixels, colorTransform); return; } #endif if (mColorBufferVk) { - mColorBufferVk->readPixelsScaled(pixelsWidth, pixelsHeight, pixelsRotation, rect, pixelsFormat, outPixels, colorTransform); + mColorBufferVk->readPixelsScaled(pixelsWidth, pixelsHeight, pixelsRotation, rect, + pixelsFormat, outPixels, colorTransform); return; } @@ -316,8 +294,9 @@ void ColorBuffer::Impl::readYuvToBytes(int x, int y, int width, int height, void GFXSTREAM_FATAL("%s: No ColorBuffer impl", __func__); } -bool ColorBuffer::Impl::updateFromBytes(int x, int y, int width, int height, GfxstreamFormat pixelsFormat, - const void* pixels, void* metadata) { +bool ColorBuffer::Impl::updateFromBytes(int x, int y, int width, int height, + GfxstreamFormat pixelsFormat, const void* pixels, + void* metadata) { touch(); #if GFXSTREAM_ENABLE_HOST_GLES @@ -350,51 +329,21 @@ bool ColorBuffer::Impl::updateGlFromBytes(const void* bytes, std::size_t bytesSi return true; } -std::unique_ptr ColorBuffer::Impl::borrowForComposition(UsedApi api, - bool isTarget) { - switch (api) { - case UsedApi::kGl: { -#if GFXSTREAM_ENABLE_HOST_GLES - if (!mColorBufferGl) { - GFXSTREAM_ERROR("%s: ColorBufferGl not available", __func__); - return nullptr; - } - return mColorBufferGl->getBorrowedImageInfo(); -#endif - } - case UsedApi::kVk: { - if (!mColorBufferVk) { - GFXSTREAM_ERROR("%s: ColorBufferVk not available", __func__); - return nullptr; - } - return mColorBufferVk->borrowForComposition(isTarget); - } - } - GFXSTREAM_ERROR("%s: Unimplemented", __func__); - return nullptr; +bool ColorBuffer::Impl::invalidateForBackend(Backend backend) { + return backend == Backend::VK ? invalidateForVk() : invalidateForGl(); +} + +bool ColorBuffer::Impl::flushFromBackend(Backend backend) { + return backend == Backend::VK ? flushFromVk() : flushFromGl(); } -std::unique_ptr ColorBuffer::Impl::borrowForDisplay(UsedApi api) { - switch (api) { - case UsedApi::kGl: { +bool ColorBuffer::Impl::importHandle(void* handle, bool preserveContent) { #if GFXSTREAM_ENABLE_HOST_GLES - if (!mColorBufferGl) { - GFXSTREAM_ERROR("%s: ColorBufferGl not available", __func__); - return nullptr; - } - return mColorBufferGl->getBorrowedImageInfo(); -#endif - } - case UsedApi::kVk: { - if (!mColorBufferVk) { - GFXSTREAM_ERROR("%s: ColorBufferVk not available", __func__); - return nullptr; - } - return mColorBufferVk->borrowForDisplay(); - } + if (mColorBufferGl) { + return mColorBufferGl->importEglNativePixmap(handle, preserveContent); } - GFXSTREAM_ERROR("%s: Unimplemented", __func__); - return nullptr; +#endif + return false; } bool ColorBuffer::Impl::flushFromGl() { @@ -512,149 +461,17 @@ std::optional ColorBuffer::Impl::exportBlob() { return mColorBufferVk->exportBlob(); } -#if GFXSTREAM_ENABLE_HOST_GLES -bool ColorBuffer::Impl::canUseGlOps() { - return (mColorBufferGl != nullptr); -} - -bool ColorBuffer::Impl::glOpBlitFromCurrentReadBuffer() { - if (!mColorBufferGl) { - GFXSTREAM_ERROR("%s: ColorBufferGl not available", __func__); - return false; - } - - touch(); - - return mColorBufferGl->blitFromCurrentReadBuffer(); -} - -bool ColorBuffer::Impl::glOpBindToTexture() { - if (!mColorBufferGl) { - GFXSTREAM_ERROR("%s: ColorBufferGl not available", __func__); - return false; - } - - touch(); - - return mColorBufferGl->bindToTexture(); -} - -bool ColorBuffer::Impl::glOpBindToTexture2() { - if (!mColorBufferGl) { - GFXSTREAM_ERROR("%s: ColorBufferGl not available", __func__); - return false; - } - - return mColorBufferGl->bindToTexture2(); -} - -bool ColorBuffer::Impl::glOpBindToRenderbuffer() { - if (!mColorBufferGl) { - GFXSTREAM_ERROR("%s: ColorBufferGl not available", __func__); - return false; - } - - touch(); - - return mColorBufferGl->bindToRenderbuffer(); -} - -bool ColorBuffer::Impl::glOpReadback(unsigned char* img, bool readbackBgra) { - if (!mColorBufferGl) { - GFXSTREAM_ERROR("%s: ColorBufferGl not available", __func__); - return false; - } - - touch(); - - return mColorBufferGl->readback(img, readbackBgra); -} - -bool ColorBuffer::Impl::glOpReadbackAsync(GLuint buffer, bool readbackBgra) { - if (!mColorBufferGl) { - GFXSTREAM_ERROR("%s: ColorBufferGl not available", __func__); - return false; - } - - touch(); - - return mColorBufferGl->readbackAsync(buffer, readbackBgra); -} - -bool ColorBuffer::Impl::glOpImportEglNativePixmap(void* pixmap, bool preserveContent) { - if (!mColorBufferGl) { - GFXSTREAM_ERROR("%s: ColorBufferGl not available", __func__); - return false; - } - - return mColorBufferGl->importEglNativePixmap(pixmap, preserveContent); -} - -bool ColorBuffer::Impl::glOpSwapYuvTexturesAndUpdate(GLenum format, GLenum type, - GfxstreamFormat texturesFormat, - GLuint* textures) { - if (!mColorBufferGl) { - GFXSTREAM_ERROR("%s: ColorBufferGl not available", __func__); - return false; - } - - mColorBufferGl->swapYUVTextures(texturesFormat, textures); - - // This makes ColorBufferGl regenerate the RGBA texture using - // YUVConverter::drawConvert() with the updated YUV textures. - mColorBufferGl->subUpdate(0, 0, mWidth, mHeight, texturesFormat, /*pixels=*/nullptr); - - flushFromGl(); - return true; -} - -bool ColorBuffer::Impl::glOpIsFastBlitSupported() const { - if (!mColorBufferGl) { - GFXSTREAM_ERROR("%s: ColorBufferGl not available", __func__); - return false; - } - - return mColorBufferGl->isFastBlitSupported(); -} - -bool ColorBuffer::Impl::glOpPostLayer(const ComposeLayer& l, int frameWidth, int frameHeight, - const std::optional>& colorTransform) { - if (!mColorBufferGl) { - GFXSTREAM_ERROR("%s: ColorBufferGl not available", __func__); - return false; - } - - mColorBufferGl->postLayer(l, frameWidth, frameHeight, colorTransform); - return true; -} - -bool ColorBuffer::Impl::glOpPostViewportScaledWithOverlay( - float rotation, float dx, float dy, float scaleX, float scaleY, - const std::optional>& colorTransform) { - if (!mColorBufferGl) { - GFXSTREAM_ERROR("%s: ColorBufferGl not available", __func__); - return false; - } - - mColorBufferGl->postViewportScaledWithOverlay(rotation, dx, dy, scaleX, scaleY, colorTransform); - return true; -} -#endif - //////////////////////////////////////////////////////////////////////////////////////////////// /*static*/ std::shared_ptr ColorBuffer::create(gl::EmulationGl* emulationGl, - vk::VkEmulation* emulationVk, - uint32_t width, - uint32_t height, - GfxstreamFormat format, - HandleType handle, - gfxstream::Stream* stream) { + vk::VkEmulation* emulationVk, uint32_t width, + uint32_t height, GfxstreamFormat format, + HandleType handle, gfxstream::Stream* stream) { std::shared_ptr colorbuffer(new ColorBuffer()); - colorbuffer->mImpl = ColorBuffer::Impl::create(emulationGl, emulationVk, width, height, format, - handle, stream); + colorbuffer->mImpl = + ColorBuffer::Impl::create(emulationGl, emulationVk, width, height, format, handle, stream); if (!colorbuffer->mImpl) { return nullptr; } @@ -681,8 +498,14 @@ void ColorBuffer::onSave(gfxstream::Stream* stream) { mImpl->onSave(stream); } void ColorBuffer::restore() { mImpl->touch(); } +void ColorBuffer::touch() { mImpl->touch(); } + HandleType ColorBuffer::getHndl() const { return mImpl->getHndl(); } +gl::ColorBufferGl* ColorBuffer::getColorBufferGl() { return mImpl->getColorBufferGl(); } + +vk::ColorBufferVk* ColorBuffer::getColorBufferVk() { return mImpl->getColorBufferVk(); } + uint32_t ColorBuffer::getWidth() const { return mImpl->getWidth(); } uint32_t ColorBuffer::getHeight() const { return mImpl->getHeight(); } @@ -706,8 +529,7 @@ void ColorBuffer::readYuvToBytes(int x, int y, int width, int height, void* outP mImpl->readYuvToBytes(x, y, width, height, outPixels, outPixelsSize); } -bool ColorBuffer::updateFromBytes(int x, int y, int width, int height, - GfxstreamFormat pixelsFormat, +bool ColorBuffer::updateFromBytes(int x, int y, int width, int height, GfxstreamFormat pixelsFormat, const void* pixels, void* metadata) { return mImpl->updateFromBytes(x, y, width, height, pixelsFormat, pixels, metadata); } @@ -716,12 +538,16 @@ bool ColorBuffer::updateGlFromBytes(const void* bytes, std::size_t bytesSize) { return mImpl->updateGlFromBytes(bytes, bytesSize); } -std::unique_ptr ColorBuffer::borrowForComposition(UsedApi api, bool isTarget) { - return mImpl->borrowForComposition(api, isTarget); +bool ColorBuffer::invalidateForBackend(Backend backend) { + return mImpl->invalidateForBackend(backend); +} + +bool ColorBuffer::flushFromBackend(Backend backend) { + return mImpl->flushFromBackend(backend); } -std::unique_ptr ColorBuffer::borrowForDisplay(UsedApi api) { - return mImpl->borrowForDisplay(api); +bool ColorBuffer::importHandle(void* handle, bool preserveContent) { + return mImpl->importHandle(handle, preserveContent); } bool ColorBuffer::flushFromGl() { return mImpl->flushFromGl(); } @@ -732,55 +558,7 @@ bool ColorBuffer::flushFromVkBytes(const void* bytes, size_t bytesSize) { return mImpl->flushFromVkBytes(bytes, bytesSize); } -bool ColorBuffer::invalidateForGl() { return mImpl->invalidateForGl(); } - -bool ColorBuffer::invalidateForVk() { return mImpl->invalidateForVk(); } - std::optional ColorBuffer::exportBlob() { return mImpl->exportBlob(); } -#if GFXSTREAM_ENABLE_HOST_GLES -bool ColorBuffer::canUseGlOps() { return mImpl->canUseGlOps(); } - -bool ColorBuffer::glOpBlitFromCurrentReadBuffer() { return mImpl->glOpBlitFromCurrentReadBuffer(); } - -bool ColorBuffer::glOpBindToTexture() { return mImpl->glOpBindToTexture(); } - -bool ColorBuffer::glOpBindToTexture2() { return mImpl->glOpBindToTexture2(); } - -bool ColorBuffer::glOpBindToRenderbuffer() { return mImpl->glOpBindToRenderbuffer(); } - -bool ColorBuffer::glOpReadback(unsigned char* img, bool readbackBgra) { - return mImpl->glOpReadback(img, readbackBgra); -} - -bool ColorBuffer::glOpReadbackAsync(GLuint buffer, bool readbackBgra) { - return mImpl->glOpReadbackAsync(buffer, readbackBgra); -} - -bool ColorBuffer::glOpImportEglNativePixmap(void* pixmap, bool preserveContent) { - return mImpl->glOpImportEglNativePixmap(pixmap, preserveContent); -} - -bool ColorBuffer::glOpSwapYuvTexturesAndUpdate(GLenum format, GLenum type, - GfxstreamFormat texturesFormat, GLuint* textures) { - return mImpl->glOpSwapYuvTexturesAndUpdate(format, type, texturesFormat, textures); -} - -bool ColorBuffer::glOpIsFastBlitSupported() const { return mImpl->glOpIsFastBlitSupported(); } - -bool ColorBuffer::glOpPostLayer(const ComposeLayer& l, int frameWidth, int frameHeight, - const std::optional>& colorTransform) { - return mImpl->glOpPostLayer(l, frameWidth, frameHeight, colorTransform); -} - -bool ColorBuffer::glOpPostViewportScaledWithOverlay( - float rotation, float dx, float dy, float scaleX, float scaleY, - const std::optional>& colorTransform) { - return mImpl->glOpPostViewportScaledWithOverlay(rotation, dx, dy, scaleX, scaleY, - colorTransform); -} - -#endif - } // namespace host } // namespace gfxstream diff --git a/host/color_buffer.h b/host/color_buffer.h index 8d38af36d..f83062007 100644 --- a/host/color_buffer.h +++ b/host/color_buffer.h @@ -14,23 +14,19 @@ #pragma once -#if GFXSTREAM_ENABLE_HOST_GLES -#include -#endif - #include #include #include -#include "framework_formats.h" -#include "gfxstream/host/borrowed_image.h" +#include "gfxstream/host/color_buffer_interface.h" #include "gfxstream/host/external_object_manager.h" +#include "gfxstream/host/framework_formats.h" #include "gfxstream/host/gfxstream_format.h" -#include "handle.h" -#include "hwc2.h" +#include "gfxstream/host/hwc2.h" +#include "gfxstream/host/handle.h" #include "render-utils/Renderer.h" #include "render-utils/stream.h" -#include "snapshot/LazySnapshotObj.h" +#include "gfxstream/host/lazy_snapshot_object.h" namespace gfxstream { namespace host { @@ -51,77 +47,48 @@ class VkEmulation; namespace gfxstream { namespace host { -class ColorBuffer : public LazySnapshotObj { +class ColorBuffer : public IColorBuffer, public LazySnapshotObj { public: static std::shared_ptr create(gl::EmulationGl* emulationGl, - vk::VkEmulation* emulationVk, - uint32_t width, - uint32_t height, - GfxstreamFormat format, - HandleType handle, - Stream* stream = nullptr); + vk::VkEmulation* emulationVk, uint32_t width, + uint32_t height, GfxstreamFormat format, + HandleType handle, Stream* stream = nullptr); static std::shared_ptr onLoad(gl::EmulationGl* emulationGl, - vk::VkEmulation* emulationVk, - Stream* stream); + vk::VkEmulation* emulationVk, Stream* stream); void onSave(Stream* stream); void restore(); + void touch() override; + + gl::ColorBufferGl* getColorBufferGl() override; + vk::ColorBufferVk* getColorBufferVk() override; - HandleType getHndl() const; - uint32_t getWidth() const; - uint32_t getHeight() const; + HandleType getHndl() const override; + uint32_t getWidth() const override; + uint32_t getHeight() const override; GfxstreamFormat getFormat() const; - void readToBytes(int x, int y, int width, int height, - GfxstreamFormat pixelsFormat, - void* outPixels, uint64_t outPixelsSize); + void readToBytes(int x, int y, int width, int height, GfxstreamFormat pixelsFormat, + void* outPixels, uint64_t outPixelsSize) override; void readToBytesScaled(int pixelsWidth, int pixelsHeight, int pixelsRotation, const Rect& rect, GfxstreamFormat pixelsFormat, void* outPixels, - const std::optional>& colorTransform); - void readYuvToBytes(int x, int y, int width, int height, void* outPixels, uint32_t outPixelsSize); - - bool updateFromBytes(int x, - int y, - int width, - int height, - GfxstreamFormat pixelsFormat, - const void* pixels, - void* metadata = nullptr); + const std::optional>& colorTransform) override; + void readYuvToBytes(int x, int y, int width, int height, void* outPixels, + uint32_t outPixelsSize) override; + + bool updateFromBytes(int x, int y, int width, int height, GfxstreamFormat pixelsFormat, + const void* pixels, void* metadata = nullptr) override; bool updateGlFromBytes(const void* bytes, std::size_t bytesSize); - enum class UsedApi { - kGl, - kVk, - }; - std::unique_ptr borrowForComposition(UsedApi api, bool isTarget); - std::unique_ptr borrowForDisplay(UsedApi api); + bool invalidateForBackend(Backend backend) override; + bool flushFromBackend(Backend backend) override; + bool importHandle(void* handle, bool preserveContent) override; bool flushFromGl(); bool flushFromVk(); bool flushFromVkBytes(const void* bytes, size_t bytesSize); - bool invalidateForGl(); - bool invalidateForVk(); - - std::optional exportBlob(); - -#if GFXSTREAM_ENABLE_HOST_GLES - bool canUseGlOps(); - bool glOpBlitFromCurrentReadBuffer(); - bool glOpBindToTexture(); - bool glOpBindToTexture2(); - bool glOpBindToRenderbuffer(); - bool glOpReadback(unsigned char* img, bool readbackBgra); - bool glOpReadbackAsync(GLuint buffer, bool readbackBgra); - bool glOpImportEglNativePixmap(void* pixmap, bool preserveContent); - bool glOpSwapYuvTexturesAndUpdate(GLenum format, GLenum type, GfxstreamFormat texturesFormat, - GLuint* textures); - bool glOpIsFastBlitSupported() const; - bool glOpPostLayer(const ComposeLayer& l, int frameWidth, int frameHeight, - const std::optional>& colorTransform); - bool glOpPostViewportScaledWithOverlay( - float rotation, float dx, float dy, float scaleX, float scaleY, - const std::optional>& colorTransform); -#endif + + std::optional exportBlob() override; private: ColorBuffer() = default; @@ -130,24 +97,9 @@ class ColorBuffer : public LazySnapshotObj { std::unique_ptr mImpl; }; -typedef std::shared_ptr ColorBufferPtr; - -struct ColorBufferRef { - ColorBufferPtr cb; - uint32_t refcount; // number of client-side references - - // Tracks whether opened at least once. In O+, - // color buffers can be created/closed immediately, - // but then registered (opened) afterwards. - bool opened; - - // Tracks the time when this buffer got a close request while not being - // opened yet. - uint64_t closedTs; -}; +using ColorBufferPtr = std::shared_ptr; -typedef std::unordered_map ColorBufferMap; -typedef std::unordered_multiset ColorBufferSet; +using ColorBufferSet = std::unordered_multiset; } // namespace host } // namespace gfxstream diff --git a/host/common/Android.bp b/host/common/Android.bp index 8437ba380..f0f6cfb9a 100644 --- a/host/common/Android.bp +++ b/host/common/Android.bp @@ -29,7 +29,9 @@ cc_library_static { "file_stream.cpp", "graphics_driver_lock.cpp", "guest_operations.cpp", + "hwc2.cpp", "mem_stream.cpp", + "post_worker.cpp", "renderer_operations.cpp", "stream_utils.cpp", "sync_device.cpp", diff --git a/host/common/BUILD.bazel b/host/common/BUILD.bazel index 394d98978..1df552727 100644 --- a/host/common/BUILD.bazel +++ b/host/common/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -18,7 +18,9 @@ cc_library( "file_stream.cpp", "graphics_driver_lock.cpp", "guest_operations.cpp", + "hwc2.cpp", "mem_stream.cpp", + "post_worker.cpp", "renderer_operations.cpp", "stream_utils.cpp", "sync_device.cpp", @@ -29,6 +31,7 @@ cc_library( copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, includes = ["include"], + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ "//common/base:gfxstream_common_base", "//common/logging:gfxstream_common_logging", diff --git a/host/common/CMakeLists.txt b/host/common/CMakeLists.txt index e04ad8d1e..dbcfc67f2 100644 --- a/host/common/CMakeLists.txt +++ b/host/common/CMakeLists.txt @@ -36,7 +36,9 @@ if (NOT TARGET gfxstream_host_common) file_stream.cpp graphics_driver_lock.cpp guest_operations.cpp + hwc2.cpp mem_stream.cpp + post_worker.cpp renderer_operations.cpp stream_utils.cpp sync_device.cpp diff --git a/host/common/address_space_operations.cpp b/host/common/address_space_operations.cpp index 010a4f3b6..496420e79 100644 --- a/host/common/address_space_operations.cpp +++ b/host/common/address_space_operations.cpp @@ -33,5 +33,13 @@ const address_space_device_control_ops &get_gfxstream_address_space_ops() { return gAddressSpaceOps; } +uint32_t get_gfxstream_guest_page_size() { + if (const auto* hwFuncs = gAddressSpaceOps.control_get_hw_funcs()) { + return hwFuncs->getGuestPageSize(); + } + // Fallback to default + return 4096; +} + } // namespace host } // namespace gfxstream \ No newline at end of file diff --git a/host/hwc2.cpp b/host/common/hwc2.cpp similarity index 86% rename from host/hwc2.cpp rename to host/common/hwc2.cpp index 12358f31e..411256dc7 100644 --- a/host/hwc2.cpp +++ b/host/common/hwc2.cpp @@ -12,13 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "hwc2.h" +#include "gfxstream/host/hwc2.h" namespace gfxstream { namespace host { -std::unique_ptr ToFlatComposeRequest( - const ComposeDevice* composeRequest) { +std::unique_ptr ToFlatComposeRequest(const ComposeDevice* composeRequest) { auto flatComposeRequest = std::make_unique(); flatComposeRequest->displayId = 0; flatComposeRequest->targetHandle = composeRequest->targetHandle; @@ -28,8 +27,7 @@ std::unique_ptr ToFlatComposeRequest( return flatComposeRequest; } -std::unique_ptr ToFlatComposeRequest( - const ComposeDevice_v2* composeRequest) { +std::unique_ptr ToFlatComposeRequest(const ComposeDevice_v2* composeRequest) { auto flatComposeRequest = std::make_unique(); flatComposeRequest->displayId = composeRequest->displayId; flatComposeRequest->targetHandle = composeRequest->targetHandle; diff --git a/host/common/include/gfxstream/host/address_space_operations.h b/host/common/include/gfxstream/host/address_space_operations.h index fb5aac36b..aa49eeec0 100644 --- a/host/common/include/gfxstream/host/address_space_operations.h +++ b/host/common/include/gfxstream/host/address_space_operations.h @@ -22,5 +22,7 @@ namespace host { void set_gfxstream_address_space_ops(const address_space_device_control_ops& ops); const address_space_device_control_ops& get_gfxstream_address_space_ops(); +uint32_t get_gfxstream_guest_page_size(); + } // namespace host } // namespace gfxstream diff --git a/host/common/include/gfxstream/host/backend_callbacks.h b/host/common/include/gfxstream/host/backend_callbacks.h deleted file mode 100644 index cd764f141..000000000 --- a/host/common/include/gfxstream/host/backend_callbacks.h +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2024 The Android Open Source Project -// -// 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 expresso or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include - -#include "gfxstream/CancelableFuture.h" - -namespace gfxstream { -namespace host { - -struct BackendCallbacks { - using RegisterProcessCleanupCallbackFunc = - std::function callback)>; - RegisterProcessCleanupCallbackFunc registerProcessCleanupCallback; - - using UnregisterProcessCleanupCallbackFunc = std::function; - UnregisterProcessCleanupCallbackFunc unregisterProcessCleanupCallback; - - using InvalidateColorBufferFunc = std::function; - InvalidateColorBufferFunc invalidateColorBuffer; - - using FlushColorBufferFunc = std::function; - FlushColorBufferFunc flushColorBuffer; - - using FlushColorBufferFromBytesFunc = - std::function; - FlushColorBufferFromBytesFunc flushColorBufferFromBytes; - - using ScheduleAsyncWorkFunc = - std::function work, std::string description)>; - ScheduleAsyncWorkFunc scheduleAsyncWork; - - using RegisterVulkanInstanceFunc = std::function; - RegisterVulkanInstanceFunc registerVulkanInstance; - - using UnregisterVulkanInstanceFunc = std::function; - UnregisterVulkanInstanceFunc unregisterVulkanInstance; -}; - -} // namespace host -} // namespace gfxstream diff --git a/host/common/include/gfxstream/host/borrowed_image.h b/host/common/include/gfxstream/host/borrowed_image.h deleted file mode 100644 index 68000ab53..000000000 --- a/host/common/include/gfxstream/host/borrowed_image.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2022 The Android Open Source Project -// -// 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 expresso or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include - -namespace gfxstream { -namespace host { - -// Common base struct representing images (Gl/Vk) that are borrowed -// by server components (e.g. CompositorGl, CompositorVk, DisplayVk) -// from the underlying server image owner (GlEmulation/VkEmulation). -struct BorrowedImageInfo { - virtual ~BorrowedImageInfo() {} - - uint32_t id = 0; - uint32_t width = 0; - uint32_t height = 0; -}; - -} // namespace host -} // namespace gfxstream diff --git a/host/common/include/gfxstream/host/color_buffer_interface.h b/host/common/include/gfxstream/host/color_buffer_interface.h new file mode 100644 index 000000000..e73c7eb98 --- /dev/null +++ b/host/common/include/gfxstream/host/color_buffer_interface.h @@ -0,0 +1,79 @@ +// Copyright 2026 The Android Open Source Project +// +// 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 expresso or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include +#include + +#include "gfxstream/host/external_object_manager.h" +#include "gfxstream/host/gfxstream_format.h" +#include "render-utils/Renderer.h" + +namespace gfxstream { +namespace host { + +namespace gl { +class ColorBufferGl; +} // namespace gl + +namespace vk { +class ColorBufferVk; +} // namespace vk + +enum class Backend { GL, VK }; + +// A (mostly) generic interface to a `ColorBuffer` so that the various backends +// interact with `ColorBuffer`s without needing to depend on all of the various +// underlying `ColorBuffer` implementations. +class IColorBuffer { + public: + virtual ~IColorBuffer() = default; + + virtual uint32_t getHndl() const = 0; + virtual uint32_t getWidth() const = 0; + virtual uint32_t getHeight() const = 0; + + virtual void touch() = 0; + + virtual gl::ColorBufferGl* getColorBufferGl() = 0; + virtual vk::ColorBufferVk* getColorBufferVk() = 0; + + virtual bool invalidateForBackend(Backend backend) = 0; + virtual bool flushFromBackend(Backend backend) = 0; + virtual bool importHandle(void* handle, bool preserveContent) = 0; + + virtual void readToBytes(int x, int y, int width, int height, GfxstreamFormat pixelsFormat, + void* outPixels, uint64_t outPixelsSize) = 0; + virtual void readToBytesScaled(int pixelsWidth, int pixelsHeight, int pixelsRotation, + const Rect& rect, GfxstreamFormat pixelsFormat, void* outPixels, + const std::optional>& colorTransform) = 0; + virtual void readYuvToBytes(int x, int y, int width, int height, void* outPixels, + uint32_t outPixelsSize) = 0; + + virtual bool updateFromBytes(int x, int y, int width, int height, GfxstreamFormat pixelsFormat, + const void* pixels, void* metadata = nullptr) = 0; + + virtual std::optional exportBlob() = 0; +}; + +// A (mostly) generic shared owning reference to a `ColorBuffer` so that the +// various backends can have shared ownership of a `ColorBuffer` without needed +// to depend on the underlying `ColorBuffer` implementations. +using IColorBufferRef = std::shared_ptr; + +} // namespace host +} // namespace gfxstream diff --git a/host/compositor.h b/host/common/include/gfxstream/host/compositor.h similarity index 92% rename from host/compositor.h rename to host/common/include/gfxstream/host/compositor.h index e42ee7068..56d71295c 100644 --- a/host/compositor.h +++ b/host/common/include/gfxstream/host/compositor.h @@ -18,8 +18,8 @@ #include #include -#include "gfxstream/host/borrowed_image.h" -#include "hwc2.h" +#include "gfxstream/host/color_buffer_interface.h" +#include "gfxstream/host/hwc2.h" #include "render-utils/Renderer.h" namespace gfxstream { @@ -31,12 +31,12 @@ class Compositor { virtual ~Compositor() {} struct CompositionRequestLayer { - std::unique_ptr source; + IColorBufferRef source; ComposeLayer props; }; struct CompositionRequest { - std::unique_ptr target; + IColorBufferRef target; std::vector layers; }; @@ -54,9 +54,7 @@ class Compositor { int screenWidth; int screenHeight; }; - std::optional getDisplayLayout() const { - return m_displayLayout; - } + std::optional getDisplayLayout() const { return m_displayLayout; } void setDisplayLayout(int screenWidth, int screenHeight, const Rect& displayRect) { if (displayRect.size.w > 0 && displayRect.size.h > 0) { DisplayLayout layout; diff --git a/host/framework_formats.h b/host/common/include/gfxstream/host/framework_formats.h similarity index 100% rename from host/framework_formats.h rename to host/common/include/gfxstream/host/framework_formats.h diff --git a/host/common/include/gfxstream/host/global_state.h b/host/common/include/gfxstream/host/global_state.h new file mode 100644 index 000000000..81f87bd2d --- /dev/null +++ b/host/common/include/gfxstream/host/global_state.h @@ -0,0 +1,72 @@ +// Copyright 2026 The Android Open Source Project +// +// 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 expresso or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +#include "gfxstream/CancelableFuture.h" +#include "gfxstream/host/color_buffer_interface.h" +#include "gfxstream/synchronization/Lock.h" + +namespace gfxstream { +namespace host { + +class GlobalState { + public: + virtual ~GlobalState() = default; + + virtual IColorBufferRef findColorBuffer(uint32_t colorBufferHandle) = 0; + virtual void openColorBufferByWindow(uint32_t colorBufferHandle) = 0; + virtual bool closeColorBufferByWindow(uint32_t colorBufferHandle) = 0; + virtual uint32_t genHandleLocked() = 0; + + virtual void registerProcessCleanupCallback(void* key, uint64_t contextId, + std::function callback) = 0; + virtual void unregisterProcessCleanupCallback(void* key) = 0; + + virtual gfxstream::base::Lock& getGlobalLock() = 0; + virtual void lockGlobalState() ACQUIRE(getGlobalLock()) = 0; + virtual void unlockGlobalState() RELEASE(getGlobalLock()) = 0; + + virtual int getColorBufferScreenshot( + IColorBuffer* cb, int targetWidth, int targetHeight, int skinRotation, + GfxstreamFormat pixelsFormat, void* outPixels, const Rect& rect, + const std::optional>& colorTransform) = 0; + + virtual float getDpr() const = 0; + virtual int windowWidth() const = 0; + virtual int windowHeight() const = 0; + virtual float getPx() const = 0; + virtual float getPy() const = 0; + virtual int getZrot() const = 0; + + virtual bool bindContext(uint32_t p_context, uint32_t p_drawSurface, + uint32_t p_readSurface) = 0; + + virtual void invalidateColorBuffer(uint32_t colorBufferHandle) = 0; + virtual void flushColorBuffer(uint32_t colorBufferHandle) = 0; + virtual void flushColorBufferFromBytes(uint32_t colorBufferHandle, const void* bytes, + size_t bytesSize) = 0; + + virtual CancelableFuture scheduleAsyncWork(std::function work, + std::string_view description) = 0; + + virtual void registerVulkanInstance(uint64_t id, std::string_view appName) const {} + virtual void unregisterVulkanInstance(uint64_t id) const {} +}; + +} // namespace host +} // namespace gfxstream diff --git a/host/handle.h b/host/common/include/gfxstream/host/handle.h similarity index 100% rename from host/handle.h rename to host/common/include/gfxstream/host/handle.h diff --git a/host/hwc2.h b/host/common/include/gfxstream/host/hwc2.h similarity index 84% rename from host/hwc2.h rename to host/common/include/gfxstream/host/hwc2.h index 936832487..9c48fa1c6 100644 --- a/host/hwc2.h +++ b/host/common/include/gfxstream/host/hwc2.h @@ -1,23 +1,24 @@ /* -* Copyright (C) 2011-2015 The Android Open Source Project -* -* 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. -*/ + * Copyright (C) 2011-2015 The Android Open Source Project + * + * 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. + */ #ifndef _LIBRENDER_HWC2_H #define _LIBRENDER_HWC2_H -#include #include + +#include #include namespace gfxstream { diff --git a/host/snapshot/include/snapshot/LazySnapshotObj.h b/host/common/include/gfxstream/host/lazy_snapshot_object.h similarity index 100% rename from host/snapshot/include/snapshot/LazySnapshotObj.h rename to host/common/include/gfxstream/host/lazy_snapshot_object.h diff --git a/host/post_commands.h b/host/common/include/gfxstream/host/post_commands.h similarity index 86% rename from host/post_commands.h rename to host/common/include/gfxstream/host/post_commands.h index 05b8c6b06..90caac749 100644 --- a/host/post_commands.h +++ b/host/common/include/gfxstream/host/post_commands.h @@ -21,16 +21,15 @@ #include #include +#include "gfxstream/host/color_buffer_interface.h" #include "gfxstream/host/display_operations.h" #include "gfxstream/host/gfxstream_format.h" -#include "handle.h" +#include "gfxstream/host/handle.h" #include "render-utils/Renderer.h" namespace gfxstream { namespace host { -class ColorBuffer; - // Posting enum class PostCmd { Post = 0, @@ -49,8 +48,7 @@ struct Post { // The block task won't stop until continueSignal is ready. std::future continueSignal; }; - using CompletionCallback = - std::function waitForGpu)>; + using CompletionCallback = std::function waitForGpu)>; PostCmd cmd; int composeVersion; std::vector composeBuffer; @@ -59,15 +57,15 @@ struct Post { HandleType cbHandle = 0; std::optional> colorTransform; - //TODO: remove union here and separate into message structures + // TODO: remove union here and separate into message structures union { - ColorBuffer* cb; + IColorBuffer* cb; struct { int width; int height; } viewport; struct { - ColorBuffer* cb; + IColorBuffer* cb; int screenwidth; int screenheight; int rotation; diff --git a/host/post_worker.h b/host/common/include/gfxstream/host/post_worker.h similarity index 84% rename from host/post_worker.h rename to host/common/include/gfxstream/host/post_worker.h index a8c2cdb17..1127f6ec5 100644 --- a/host/post_worker.h +++ b/host/common/include/gfxstream/host/post_worker.h @@ -21,27 +21,25 @@ #include #include -#include "compositor.h" -#include "hwc2.h" -#include "post_commands.h" #include "gfxstream/Compiler.h" +#include "gfxstream/host/color_buffer_interface.h" +#include "gfxstream/host/compositor.h" #include "gfxstream/host/gfxstream_format.h" - +#include "gfxstream/host/global_state.h" +#include "gfxstream/host/hwc2.h" +#include "post_commands.h" namespace gfxstream { namespace host { -class ColorBuffer; -class FrameBuffer; -struct RenderThreadInfo; class PostWorker { public: - PostWorker(bool mainThreadPostingOnly, FrameBuffer* fb, Compositor* compositor); + PostWorker(bool mainThreadPostingOnly, GlobalState* globalState, Compositor* compositor); virtual ~PostWorker(); // post: posts the next color buffer. // Assumes framebuffer lock is held. - void post(ColorBuffer* cb, std::unique_ptr postCallback, + void post(IColorBuffer* cb, std::unique_ptr postCallback, const std::optional>& colorTransform); // viewport: (re)initializes viewport dimensions. @@ -61,7 +59,7 @@ class PostWorker { void clear(); // screenshot: readbacks emulator display image to a buffer - void screenshot(ColorBuffer* cb, int screenwidth, int screenheight, int skinRotation, + void screenshot(IColorBuffer* cb, int screenwidth, int screenheight, int skinRotation, GfxstreamFormat pixelsFormat, void* outPixels, const Rect& rect, const std::optional>& colorTransform); @@ -75,15 +73,15 @@ class PostWorker { protected: void runTask(std::packaged_task); // Impl versions of the above, so we can run it from separate threads - virtual std::shared_future postImpl(ColorBuffer* cb, - const std::optional>& colorTransform) = 0; + virtual std::shared_future postImpl( + IColorBuffer* cb, const std::optional>& colorTransform) = 0; virtual void viewportImpl(int width, int height) = 0; virtual void clearImpl() = 0; virtual void exitImpl() = 0; virtual std::shared_future composeImpl(const FlatComposeRequest& composeRequest); protected: - FrameBuffer* mFb; + GlobalState* m_globalState; Compositor* m_compositor = nullptr; protected: diff --git a/host/readback_worker.h b/host/common/include/gfxstream/host/readback_worker.h similarity index 67% rename from host/readback_worker.h rename to host/common/include/gfxstream/host/readback_worker.h index b5a638d44..9b3d53bba 100644 --- a/host/readback_worker.h +++ b/host/common/include/gfxstream/host/readback_worker.h @@ -1,18 +1,18 @@ /* -* Copyright (C) 2017 The Android Open Source Project -* -* 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. -*/ + * Copyright (C) 2017 The Android Open Source Project + * + * 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. + */ #pragma once #include @@ -20,12 +20,12 @@ namespace gfxstream { namespace host { -class ColorBuffer; +class IColorBuffer; // This class implements async readback of ColorBuffers on both the FrameBuffer // posting thread and a separate worker thread. class ReadbackWorker { - public: + public: virtual ~ReadbackWorker() = default; virtual void init() = 0; @@ -37,9 +37,9 @@ class ReadbackWorker { virtual void deinitReadbackForDisplay(uint32_t displayId) = 0; enum class DoNextReadbackResult { - OK_NOT_READY_FOR_READ, + OK_NOT_READY_FOR_READ, - OK_READY_FOR_READ, + OK_READY_FOR_READ, }; // doNextReadback(): Call this from the emugl FrameBuffer::post thread @@ -52,11 +52,10 @@ class ReadbackWorker { // |readbackBgra|: Whether to force the readback format as GL_BGRA_EXT, // so that we get (depending on driver quality, heh) a gpu conversion of the // readback image that is suitable for webrtc, which expects formats like that. - virtual DoNextReadbackResult doNextReadback(uint32_t displayId, - ColorBuffer* cb, - void* fbImage, - bool repaint, - bool readbackBgra) = 0; + virtual DoNextReadbackResult doNextReadback(uint32_t displayId, IColorBuffer* cb, void* fbImage, + bool repaint, bool readbackBgra) = 0; + + virtual void doNextReadbackSync(IColorBuffer* cb, void* fbImage, bool readbackBgra) = 0; // Retrieves the latest framebuffer that has been posted and read with // doNextReadback. This is meant for apps like video encoding to use as @@ -69,11 +68,11 @@ class ReadbackWorker { // This is usually called when there was no doNextReadback activity // for a few ms, to guarantee that end users see the final frame. enum class FlushResult { - FAIL, + FAIL, - OK_NOT_READY_FOR_READ, + OK_NOT_READY_FOR_READ, - OK_READY_FOR_READ, + OK_READY_FOR_READ, }; virtual FlushResult flushPipeline(uint32_t displayId) = 0; diff --git a/host/common/meson.build b/host/common/meson.build index 44cff945c..d83d432c6 100644 --- a/host/common/meson.build +++ b/host/common/meson.build @@ -13,7 +13,9 @@ files_lib_host_common = files( 'file_stream.cpp', 'graphics_driver_lock.cpp', 'guest_operations.cpp', + 'hwc2.cpp', 'mem_stream.cpp', + 'post_worker.cpp', 'renderer_operations.cpp', 'stream_utils.cpp', 'sync_device.cpp', @@ -27,6 +29,7 @@ lib_host_common = static_library( include_directories: [ inc_common_base, inc_common_logging, + inc_common_utils, inc_gfxstream_server, inc_host_address_space, inc_host_common, @@ -34,6 +37,7 @@ lib_host_common = static_library( link_with: [ lib_common_base, lib_common_logging, + lib_common_utils, lib_host_address_space, ], ) \ No newline at end of file diff --git a/host/post_worker.cpp b/host/common/post_worker.cpp similarity index 67% rename from host/post_worker.cpp rename to host/common/post_worker.cpp index 53041dcd3..38c59b84b 100644 --- a/host/post_worker.cpp +++ b/host/common/post_worker.cpp @@ -1,43 +1,41 @@ /* -* Copyright (C) 2017 The Android Open Source Project -* -* 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 "post_worker.h" + * Copyright (C) 2017 The Android Open Source Project + * + * 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 "gfxstream/host/post_worker.h" #include #include -#include "color_buffer.h" -#include "frame_buffer.h" -#include "render_thread_info.h" #include "gfxstream/Tracing.h" #include "gfxstream/common/logging.h" +#include "gfxstream/host/color_buffer_interface.h" +#include "gfxstream/host/global_state.h" #include "gfxstream/host/window_operations.h" -#include "vulkan/vk_common_operations.h" namespace gfxstream { namespace host { -PostWorker::PostWorker(bool mainThreadPostingOnly, FrameBuffer* fb, Compositor* compositor) - : mFb(fb), +PostWorker::PostWorker(bool mainThreadPostingOnly, gfxstream::host::GlobalState* globalState, + Compositor* compositor) + : m_globalState(globalState), m_compositor(compositor), m_mainThreadPostingOnly(mainThreadPostingOnly) {} std::shared_future PostWorker::composeImpl(const FlatComposeRequest& composeRequest) { - std::shared_future completedFuture = - std::async(std::launch::deferred, [] {}).share(); + std::shared_future completedFuture = std::async(std::launch::deferred, [] {}).share(); completedFuture.wait(); if (!isComposeTargetReady(composeRequest.targetHandle)) { @@ -45,8 +43,7 @@ std::shared_future PostWorker::composeImpl(const FlatComposeRequest& compo } Compositor::CompositionRequest compositorRequest = {}; - compositorRequest.target = mFb->borrowColorBufferForComposition(composeRequest.targetHandle, - /*colorBufferIsTarget=*/true); + compositorRequest.target = m_globalState->findColorBuffer(composeRequest.targetHandle); if (!compositorRequest.target) { GFXSTREAM_ERROR("Compose target is null (cb=0x%x).", composeRequest.targetHandle); return completedFuture; @@ -58,8 +55,7 @@ std::shared_future PostWorker::composeImpl(const FlatComposeRequest& compo auto& compositorLayer = compositorRequest.layers.emplace_back(); compositorLayer.props = guestLayer; } else { - auto source = mFb->borrowColorBufferForComposition(guestLayer.cbHandle, - /*colorBufferIsTarget=*/false); + auto source = m_globalState->findColorBuffer(guestLayer.cbHandle); if (!source) { continue; } @@ -92,14 +88,13 @@ void PostWorker::block(std::promise scheduledSignal, std::future con PostWorker::~PostWorker() {} -void PostWorker::post(ColorBuffer* cb, std::unique_ptr postCallback, - const std::optional>& colorTransform) { +void PostWorker::post(IColorBuffer* cb, std::unique_ptr postCallback, + const std::optional>& colorTransform) { auto packagedPostCallback = std::shared_ptr(std::move(postCallback)); - runTask( - std::packaged_task([cb, packagedPostCallback, this, colorTransform] { - auto completedFuture = postImpl(cb, colorTransform); - (*packagedPostCallback)(completedFuture); - })); + runTask(std::packaged_task([cb, packagedPostCallback, this, colorTransform] { + auto completedFuture = postImpl(cb, colorTransform); + (*packagedPostCallback)(completedFuture); + })); } void PostWorker::exit() { @@ -107,8 +102,7 @@ void PostWorker::exit() { } void PostWorker::viewport(int width, int height) { - runTask(std::packaged_task( - [width, height, this] { viewportImpl(width, height); })); + runTask(std::packaged_task([width, height, this] { viewportImpl(width, height); })); } void PostWorker::compose(std::unique_ptr composeRequest, @@ -118,29 +112,28 @@ void PostWorker::compose(std::unique_ptr composeRequest, auto packagedComposeCallback = std::shared_ptr(std::move(composeCallback)); auto packagedComposeRequest = std::shared_ptr(std::move(composeRequest)); - runTask( - std::packaged_task([packagedComposeCallback, packagedComposeRequest, this] { + runTask(std::packaged_task([packagedComposeCallback, packagedComposeRequest, this] { auto completedFuture = composeImpl(*packagedComposeRequest); m_composeTargetToComposeFuture.emplace(packagedComposeRequest->targetHandle, completedFuture); (*packagedComposeCallback)(completedFuture); - })); + })); } void PostWorker::clear() { runTask(std::packaged_task([this] { clearImpl(); })); } -void PostWorker::screenshot(ColorBuffer* cb, int screenwidth, int screenheight, int skinRotation, +void PostWorker::screenshot(IColorBuffer* cb, int screenwidth, int screenheight, int skinRotation, GfxstreamFormat pixelsFormat, void* outPixels, const Rect& rect, const std::optional>& colorTransform) { // See b/292237104. - mFb->lock(); + m_globalState->lockGlobalState(); - mFb->getColorBufferScreenshot(cb, screenwidth, screenheight, skinRotation, pixelsFormat, - outPixels, rect, colorTransform); + m_globalState->getColorBufferScreenshot(cb, screenwidth, screenheight, skinRotation, + pixelsFormat, outPixels, rect, colorTransform); - mFb->unlock(); + m_globalState->unlockGlobalState(); } namespace { @@ -160,8 +153,8 @@ void PostWorker::runTask(std::packaged_task task) { if (!get_gfxstream_window_operations().run_on_ui_thread) { GFXSTREAM_ERROR("m_runOnUiThread function ptr is NULL, going to crash"); } - get_gfxstream_window_operations() - .run_on_ui_thread(RunOnUiThreadTrampoline, taskPtr.release(), false); + get_gfxstream_window_operations().run_on_ui_thread(RunOnUiThreadTrampoline, + taskPtr.release(), false); } else { (*taskPtr)(); } diff --git a/host/compressed_textures/BUILD.bazel b/host/compressed_textures/BUILD.bazel index 9a0e4e1f9..a2d295519 100644 --- a/host/compressed_textures/BUILD.bazel +++ b/host/compressed_textures/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -14,6 +14,7 @@ cc_library( hdrs = glob(["include/**/*.h"]), copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, + linkopts = GFXSTREAM_HOST_LINKOPTS, strip_include_prefix = "include", deps = [ "//common/etc:gfxstream_etc", @@ -26,6 +27,7 @@ cc_test( "astc_cpu_decompressor_unittest.cpp", ], copts = GFXSTREAM_HOST_COPTS, + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ ":gfxstream_host_compressed_textures", "@com_google_googletest//:gtest", diff --git a/host/decoder_common/Android.bp b/host/decoder_common/Android.bp index 3c914e240..09ac25589 100644 --- a/host/decoder_common/Android.bp +++ b/host/decoder_common/Android.bp @@ -33,6 +33,9 @@ cc_library_static { "libgfxstream_host_library", "libgfxstream_common_logging", ], + export_static_lib_headers: [ + "libgfxstream_common_base", + ], cflags: ["-fvisibility=hidden"], export_include_dirs: [ "include", diff --git a/host/decoder_common/BUILD.bazel b/host/decoder_common/BUILD.bazel index 585e759cf..b58dc67ba 100644 --- a/host/decoder_common/BUILD.bazel +++ b/host/decoder_common/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -27,6 +27,7 @@ cc_library( ".", "include", ], + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ "//common/base:gfxstream_common_base", "//common/logging:gfxstream_common_logging", diff --git a/host/features/BUILD.bazel b/host/features/BUILD.bazel index f0bbe8712..8618b5375 100644 --- a/host/features/BUILD.bazel +++ b/host/features/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -13,6 +13,7 @@ cc_library( copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, includes = ["include"], + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ "//common/logging:gfxstream_common_logging", "//common/utils:gfxstream_common_utils", @@ -25,6 +26,7 @@ cc_test( "features_unittest.cpp", ], copts = GFXSTREAM_HOST_COPTS, + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ ":gfxstream_host_features", "@com_google_googletest//:gtest", diff --git a/host/features/features.cpp b/host/features/features.cpp index 52880599f..2b598c4f6 100644 --- a/host/features/features.cpp +++ b/host/features/features.cpp @@ -81,7 +81,7 @@ bool U32FeatureInfo::parseValue(std::string_view strValue) { uint32_t val; auto res = std::from_chars(strValue.data() + valueStart, strValue.data() + strValue.size(), val, valueBase); - if (res.ec == std::errc()) { + if (res.ec == std::errc() && res.ptr == strValue.data() + strValue.size()) { value = U32FeatureValue(val); return true; } @@ -95,13 +95,50 @@ std::string U32FeatureInfo::getValueReadable() const { return "(Unset)"; } - // E.g. '123 (0x7B)' + // E.g. '123 (0x7b)' const uint32_t val = u32ValueOpt.value(); std::ostringstream oss; oss << val << " (0x" << std::hex << val << ")"; return oss.str(); } +bool U64FeatureInfo::parseValue(std::string_view strValue) { + if (strValue.empty()) { + value = U64FeatureValue(std::nullopt); + return true; + } + int valueStart = 0; + int valueBase = 10; + // Check if the value is given as a hexadecimal value + if (strValue.size() > 2 && strValue[0] == '0' && + (strValue[1] == 'x' || strValue[1] == 'X')) { + valueStart = 2; + valueBase = 16; + } + uint64_t val; + auto res = std::from_chars(strValue.data() + valueStart, strValue.data() + strValue.size(), + val, valueBase); + if (res.ec == std::errc() && res.ptr == strValue.data() + strValue.size()) { + value = U64FeatureValue(val); + return true; + } + GFXSTREAM_ERROR("Cannot parse '%.*s' for feature '%s'", (int)strValue.size(), strValue.data(), name.c_str()); + return false; +} + +std::string U64FeatureInfo::getValueReadable() const { + auto u64ValueOpt = std::get(value); + if (!u64ValueOpt) { + return "(Unset)"; + } + + // E.g. '123 (0x7b)' + const uint64_t val = u64ValueOpt.value(); + std::ostringstream oss; + oss << val << " (0x" << std::hex << val << ")"; + return oss.str(); +} + bool VulkanVersionFeatureInfo::parseValue(std::string_view strValue) { // Parse vulkan version info, can be in 1.2, 1.2.3 or integer format if (strValue.find('.') != std::string_view::npos) { @@ -114,7 +151,8 @@ bool VulkanVersionFeatureInfo::parseValue(std::string_view strValue) { pos = (ptr - strValue.data()) + 1; // Skip the dot } - value = VK_MAKE_API_VERSION(0, parts[0], parts[1], parts[2]); + uint32_t val = VK_MAKE_API_VERSION(0, parts[0], parts[1], parts[2]); + value = U32FeatureValue(val); return true; } diff --git a/host/features/features_unittest.cpp b/host/features/features_unittest.cpp index 5db2781e5..d7cdd50f8 100644 --- a/host/features/features_unittest.cpp +++ b/host/features/features_unittest.cpp @@ -105,6 +105,62 @@ TEST_F(FeaturesTest, U32FeatureInfoTest) { EXPECT_FALSE(u32Feature.parseValue("invalid_number")); } +TEST_F(FeaturesTest, U64FeatureInfoTest) { + FeatureMap map; + U64FeatureInfo u64Feature("TestU64", "Description", &map); + + EXPECT_EQ(u64Feature.getName(), "TestU64"); + EXPECT_FALSE(u64Feature.getValue().has_value()); + EXPECT_EQ(u64Feature.getValueReadable(), "(Unset)"); + + EXPECT_TRUE(u64Feature.parseValue("123")); + ASSERT_TRUE(u64Feature.getValue().has_value()); + EXPECT_EQ(u64Feature.getValue().value(), 123uLL); + EXPECT_EQ(u64Feature.getValueReadable(), "123 (0x7b)"); + + EXPECT_TRUE(u64Feature.parseValue("0x7B")); + ASSERT_TRUE(u64Feature.getValue().has_value()); + EXPECT_EQ(u64Feature.getValue().value(), 123uLL); + EXPECT_EQ(u64Feature.getValueReadable(), "123 (0x7b)"); + + EXPECT_TRUE(u64Feature.parseValue("0")); + ASSERT_TRUE(u64Feature.getValue().has_value()); + EXPECT_EQ(u64Feature.getValue().value(), 0uLL); + EXPECT_EQ(u64Feature.getValueReadable(), "0 (0x0)"); + + // Test a number that requires > 32 bits, e.g. 5000000000 (0x12A05F200) + EXPECT_TRUE(u64Feature.parseValue("5000000000")); + ASSERT_TRUE(u64Feature.getValue().has_value()); + EXPECT_EQ(u64Feature.getValue().value(), 5000000000uLL); + EXPECT_EQ(u64Feature.getValueReadable(), "5000000000 (0x12a05f200)"); + + EXPECT_TRUE(u64Feature.parseValue("0x12A05F200")); + ASSERT_TRUE(u64Feature.getValue().has_value()); + EXPECT_EQ(u64Feature.getValue().value(), 5000000000uLL); + EXPECT_EQ(u64Feature.getValueReadable(), "5000000000 (0x12a05f200)"); + + EXPECT_TRUE(u64Feature.parseValue("")); + EXPECT_FALSE(u64Feature.getValue().has_value()); + EXPECT_EQ(u64Feature.getValueReadable(), "(Unset)"); + + EXPECT_FALSE(u64Feature.parseValue("invalid_number")); + + u64Feature.setValue(999uLL); + ASSERT_TRUE(u64Feature.getValue().has_value()); + EXPECT_EQ(u64Feature.getValue().value(), 999uLL); + EXPECT_EQ(u64Feature.getValueReadable(), "999 (0x3e7)"); + + u64Feature.setValue(18446744073709551615uLL); + ASSERT_TRUE(u64Feature.getValue().has_value()); + EXPECT_EQ(u64Feature.getValue().value(), 18446744073709551615uLL); + EXPECT_EQ(u64Feature.getValueReadable(), "18446744073709551615 (0xffffffffffffffff)"); + + EXPECT_TRUE(u64Feature.parseValue("18446744073709551615")); + ASSERT_TRUE(u64Feature.getValue().has_value()); + EXPECT_EQ(u64Feature.getValue().value(), 18446744073709551615uLL); + EXPECT_EQ(u64Feature.getValueReadable(), "18446744073709551615 (0xffffffffffffffff)"); +} + TEST_F(FeaturesTest, VulkanVersionFeatureInfoTest) { FeatureMap map; VulkanVersionFeatureInfo vkVersionFeature("TestVkVersion", "Description", &map); diff --git a/host/features/include/gfxstream/host/features.h b/host/features/include/gfxstream/host/features.h index 5e11fe3bb..98d00e589 100644 --- a/host/features/include/gfxstream/host/features.h +++ b/host/features/include/gfxstream/host/features.h @@ -32,7 +32,8 @@ using FeatureMap = std::map; // The potential types for the "value" of a given feature using StringFeatureValue = std::optional; using U32FeatureValue = std::optional; -using FeatureValue = std::variant; +using U64FeatureValue = std::optional; +using FeatureValue = std::variant; class FeatureInfoBase { public: @@ -96,13 +97,23 @@ class U32FeatureInfo : public FeatureInfoBase { std::string getValueReadable() const override; }; +class U64FeatureInfo : public FeatureInfoBase { + public: + U64FeatureInfo(std::string_view name, std::string_view description, FeatureMap* map) + : FeatureInfoBase(name, description, map, U64FeatureValue(std::nullopt)) {} + + U64FeatureValue getValue() const { return std::get(value); } + void setValue(uint64_t val) { value = U64FeatureValue(val); } + + bool parseValue(std::string_view strValue) override; + std::string getValueReadable() const override; +}; + class VulkanVersionFeatureInfo : public U32FeatureInfo { public: VulkanVersionFeatureInfo(std::string_view name, std::string_view description, FeatureMap* map) : U32FeatureInfo(name, description, map) {} - U32FeatureValue getValue() const { return std::get(value); } - bool parseValue(std::string_view strValue) override; std::string getValueReadable() const override; }; @@ -438,6 +449,11 @@ struct FeatureSet { " not related to the host vulkan level available or used.", &map, }; + U64FeatureInfo VulkanMaxSafeHeapSize = { + "VulkanMaxSafeHeapSize", + "If set to a non-zero value, limits the memory heap size reported to the guest (in bytes).", + &map, + }; }; #define GFXSTREAM_SET_BOOL_FEATURE_ON_CONDITION(set, feature, condition) \ diff --git a/host/frame_buffer.cpp b/host/frame_buffer.cpp index 2585ee199..59f6b8de4 100644 --- a/host/frame_buffer.cpp +++ b/host/frame_buffer.cpp @@ -18,13 +18,14 @@ #include #include -#include - -#include - #if defined(__linux__) #include #endif +#include + +#include +#include +#include #if GFXSTREAM_ENABLE_HOST_GLES #include "host/gl/gles_version_detector.h" @@ -38,25 +39,27 @@ #include "gl/glestranslator/egl/egl_global_info.h" #endif -#include "host/gl/context_helper.h" -#include "hwc2.h" -#include "native_sub_window.h" -#include "render_thread_info.h" -#include "sync_thread.h" -#include "gfxstream/shared_library.h" +#include "color_buffer.h" #include "gfxstream/Tracing.h" #include "gfxstream/common/logging.h" #include "gfxstream/containers/Lookup.h" -#include "gfxstream/host/tracing.h" #include "gfxstream/host/display_operations.h" +#include "gfxstream/host/global_state.h" #include "gfxstream/host/guest_operations.h" +#include "gfxstream/host/hwc2.h" +#include "gfxstream/host/native_sub_window.h" #include "gfxstream/host/renderer_operations.h" #include "gfxstream/host/stream_utils.h" +#include "gfxstream/host/tracing.h" #include "gfxstream/host/vm_operations.h" #include "gfxstream/host/window_operations.h" +#include "gfxstream/shared_library.h" #include "gfxstream/synchronization/Lock.h" #include "gfxstream/system/System.h" +#include "host/gl/context_helper.h" #include "render-utils/MediaNative.h" +#include "render_thread_info.h" +#include "sync_thread.h" #include "vulkan/display_vk.h" #include "vulkan/post_worker_vk.h" #include "vulkan/vk_common_operations.h" @@ -75,25 +78,15 @@ using gfxstream::host::gl::GLESApi_CM; #if GFXSTREAM_ENABLE_HOST_GLES using gfxstream::host::gl::ContextHelper; using gfxstream::host::gl::DisplaySurfaceGl; -using gfxstream::host::gl::EmulatedEglConfig; -using gfxstream::host::gl::EmulatedEglConfigList; using gfxstream::host::gl::EmulatedEglContext; -using gfxstream::host::gl::EmulatedEglContextMap; -using gfxstream::host::gl::EmulatedEglContextPtr; using gfxstream::host::gl::EmulatedEglFenceSync; using gfxstream::host::gl::EmulatedEglWindowSurface; -using gfxstream::host::gl::EmulatedEglWindowSurfaceMap; -using gfxstream::host::gl::EmulatedEglWindowSurfacePtr; using gfxstream::host::gl::EmulationGl; using gfxstream::host::gl::GLES_DISPATCH_MAX_VERSION_2; using gfxstream::host::gl::GLESDispatchMaxVersion; using gfxstream::host::gl::PostWorkerGl; using gfxstream::host::gl::RecursiveScopedContextBind; -using gfxstream::host::gl::RenderThreadInfoGl; -using gfxstream::host::gl::s_egl; -using gfxstream::host::gl::s_gles2; using gfxstream::host::gl::TextureDraw; -using gfxstream::host::gl::YUVConverter; #endif using gfxstream::host::vk::AstcEmulationMode; using gfxstream::host::vk::VkEmulation; @@ -281,28 +274,6 @@ std::optional GetGfxstreamFormat( } } -std::optional GetGfxstreamFormat( - const gfxstream::host::FeatureSet& features, - FrameworkFormat format) { - switch (format) { - case FRAMEWORK_FORMAT_NV12: - return GfxstreamFormat::NV12; - case FRAMEWORK_FORMAT_YV12: - return GfxstreamFormat::YV12; - case FRAMEWORK_FORMAT_P010: - return GfxstreamFormat::P010; - case FRAMEWORK_FORMAT_YUV_420_888: { - if (features.Yuv420888ToNv21.enabled()) { - return GfxstreamFormat::NV21; - } else { - return GfxstreamFormat::YV21; - } - } - default: - return std::nullopt; - } -} - static std::optional> GetColorTransform(uint32_t displayId = 0) { float displayColorTransformData[16]; if (get_gfxstream_multi_display_operations().get_color_transform_matrix( @@ -345,6 +316,13 @@ typedef std::unordered_map ProcOwnedEmulate typedef std::unordered_map ProcOwnedEmulatedEGLImages; #endif // GFXSTREAM_ENABLE_HOST_GLES +struct ReferenceCountedColorBuffer { + ColorBufferPtr cb; + uint32_t refcount; // number of client-side references + bool opened; + uint64_t closedTs; +}; + typedef std::unordered_map BufferMap; typedef std::unordered_multiset BufferSet; typedef std::unordered_map ProcOwnedBuffers; @@ -353,7 +331,8 @@ typedef std::unordered_map ProcOwnedColorBuffers; typedef std::unordered_map> CallbackMap; typedef std::unordered_map ProcOwnedCleanupCallbacks; -class FrameBuffer::Impl : public gfxstream::base::EventNotificationSupport { +class FrameBuffer::Impl : public gfxstream::base::EventNotificationSupport, + public GlobalState { public: static std::unique_ptr Create(FrameBuffer* framebuffer, uint32_t width, uint32_t height, const FeatureSet& features, bool useSubWindow); @@ -472,15 +451,24 @@ class FrameBuffer::Impl : public gfxstream::base::EventNotificationSupportlockContextStructureRead(); + } + } + void unlockContextStructureRead() { + if (m_emulationGl) { + m_emulationGl->unlockContextStructureRead(); + } + } // For use with sync threads and otherwise, any time we need a GL context // not specifically for drawing, but to obtain certain things about // GL state. // It can be unsafe / leaky to change the structure of contexts // outside the facilities the FrameBuffer class provides. - void createTrivialContext(HandleType shared, HandleType* contextOut, HandleType* surfOut); + void createTrivialContext(HandleType shared, HandleType* contextOut, + HandleType* surfOut) NO_THREAD_SAFETY_ANALYSIS; void setShuttingDown() { m_shuttingDown = true; } bool isShuttingDown() const { return m_shuttingDown; } @@ -490,27 +478,28 @@ class FrameBuffer::Impl : public gfxstream::base::EventNotificationSupport>& colorTransform); + int getColorBufferScreenshot( + IColorBuffer* cb, int targetWidth, int targetHeight, int skinRotation, + GfxstreamFormat pixelsFormat, void* outPixels, const Rect& rect, + const std::optional>& colorTransform) override; void onLastColorBufferRef(uint32_t handle); - ColorBufferPtr findColorBuffer(HandleType p_colorbuffer); + + IColorBufferRef findColorBuffer(HandleType p_colorbuffer) override; + void openColorBufferByWindow(uint32_t colorBufferHandle) override; + bool closeColorBufferByWindow(uint32_t colorBufferHandle) override; + uint32_t genHandleLocked() override; BufferPtr findBuffer(HandleType p_buffer); void registerProcessCleanupCallback(void* key, uint64_t contextId, - std::function callback); - void unregisterProcessCleanupCallback(void* key); + std::function callback) override; + void unregisterProcessCleanupCallback(void* key) override; + + gfxstream::base::Lock& getGlobalLock() override LOCK_RETURNED(m_lock); + void lockGlobalState() override ACQUIRE(getGlobalLock()); + void unlockGlobalState() override RELEASE(getGlobalLock()); + + void invalidateColorBuffer(uint32_t colorBufferHandle) override; + void flushColorBuffer(uint32_t colorBufferHandle) override; + void flushColorBufferFromBytes(uint32_t colorBufferHandle, const void* bytes, + size_t bytesSize) override; + CancelableFuture scheduleAsyncWork(std::function work, + std::string_view description) override; const ProcessResources* getProcessResources(uint64_t puid); @@ -573,10 +577,6 @@ class FrameBuffer::Impl : public gfxstream::base::EventNotificationSupport borrowColorBufferForComposition(uint32_t colorBufferHandle, - bool colorBufferIsTarget); - std::unique_ptr borrowColorBufferForDisplay(uint32_t colorBufferHandle); void logVulkanDeviceLost(); void setVsyncHz(int vsyncHz); @@ -602,8 +602,9 @@ class FrameBuffer::Impl : public gfxstream::base::EventNotificationSupport cleanupProcGLObjects_locked(uint64_t puid, bool forced = false); - void markOpened(ColorBufferRef* cbRef); + void markOpened(ReferenceCountedColorBuffer* cbRef); // Returns true if the color buffer was erased. bool closeColorBufferLocked(HandleType p_colorbuffer, bool forced = false); // Returns true if this was the last ref and we need to destroy stuff. @@ -857,12 +844,11 @@ class FrameBuffer::Impl : public gfxstream::base::EventNotificationSupport m_colorbuffers; BufferMap m_buffers; // A collection of color buffers that were closed without any usages @@ -981,6 +967,10 @@ class FrameBuffer::Impl : public gfxstream::base::EventNotificationSupport m_displaySurface; +#if GFXSTREAM_ENABLE_HOST_GLES + gl::DisplayGl* m_displayGl = nullptr; +#endif + // CompositorGl. // TODO: update RenderDoc to be a DisplaySurfaceUser. std::vector m_displaySurfaceUsers; @@ -1074,26 +1064,6 @@ class FrameBuffer::Impl : public gfxstream::base::EventNotificationSupport m_EmulatedEglWindowSurfaceToColorBuffer; - - ProcOwnedEmulatedEGLImages m_procOwnedEmulatedEglImages; - ProcOwnedEmulatedEglContexts m_procOwnedEmulatedEglContexts; - ProcOwnedEmulatedEglWindowSurfaces m_procOwnedEmulatedEglWindowSurfaces; - gl::DisplayGl* m_displayGl = nullptr; - - struct PlatformEglContextInfo { - EGLContext context; - EGLSurface surface; - }; - - std::unordered_map m_platformEglContexts; -#endif }; void MaybeIncreaseFileDescriptorSoftLimit() { @@ -1239,48 +1209,7 @@ std::unique_ptr FrameBuffer::Impl::Create(FrameBuffer* frameb if (impl->m_features.Vulkan.enabled()) { vkDispatch = vk::vkDispatch(false /* not for testing */); - gfxstream::host::BackendCallbacks callbacks{ - .registerProcessCleanupCallback = - [impl = impl.get()](void* key, uint64_t contextId, std::function callback) { - impl->registerProcessCleanupCallback(key, contextId, callback); - }, - .unregisterProcessCleanupCallback = - [impl = impl.get()](void* key) { impl->unregisterProcessCleanupCallback(key); }, - .invalidateColorBuffer = - [impl = impl.get()](uint32_t colorBufferHandle) { - impl->invalidateColorBufferForVk(colorBufferHandle); - }, - .flushColorBuffer = - [impl = impl.get()](uint32_t colorBufferHandle) { - impl->flushColorBufferFromVk(colorBufferHandle); - }, - .flushColorBufferFromBytes = - [impl = impl.get()](uint32_t colorBufferHandle, const void* bytes, - size_t bytesSize) { - impl->flushColorBufferFromVkBytes(colorBufferHandle, bytes, bytesSize); - }, - .scheduleAsyncWork = - [impl = impl.get()](std::function work, std::string description) { - auto promise = std::make_shared(); - auto future = promise->GetFuture(); - SyncThread::get()->triggerGeneral( - [promise = std::move(promise), work = std::move(work)]() mutable { - work(); - promise->MarkComplete(); - }, - description); - return future; - }, -#ifdef CONFIG_AEMU - .registerVulkanInstance = - [impl = impl.get()](uint64_t id, const char* appName) { - impl->registerVulkanInstance(id, appName); - }, - .unregisterVulkanInstance = - [impl = impl.get()](uint64_t id) { impl->unregisterVulkanInstance(id); }, -#endif - }; - impl->m_emulationVk = vk::VkEmulation::create(vkDispatch, callbacks, impl->m_features); + impl->m_emulationVk = vk::VkEmulation::create(vkDispatch, impl.get(), impl->m_features); if (!impl->m_emulationVk) { GFXSTREAM_ERROR( "Failed to initialize global Vulkan emulation requested. Try updating your GPU " @@ -1337,7 +1266,7 @@ std::unique_ptr FrameBuffer::Impl::Create(FrameBuffer* frameb // Do not initialize GL emulation if the guest is using ANGLE. if (needEmulationGl) { impl->m_emulationGl = - EmulationGl::create(width, height, impl->m_features, useSubWindow); + EmulationGl::create(width, height, impl->m_features, useSubWindow, impl.get()); if (!impl->m_emulationGl) { GFXSTREAM_ERROR("Failed to initialize GL emulation."); return nullptr; @@ -1509,13 +1438,13 @@ std::unique_ptr FrameBuffer::Impl::Create(FrameBuffer* frameb if (impl->m_useVulkanComposition) { impl->m_postWorker.reset( - new PostWorkerVk(framebuffer, impl->m_compositor, impl->m_displayVk)); + new PostWorkerVk(impl.get(), impl->m_compositor, impl->m_displayVk)); } else { const bool shouldPostOnlyOnMainThread = postOnlyOnMainThread(); #if GFXSTREAM_ENABLE_HOST_GLES PostWorkerGl* postWorkerGl = - new PostWorkerGl(shouldPostOnlyOnMainThread, framebuffer, impl->m_compositor, + new PostWorkerGl(shouldPostOnlyOnMainThread, impl.get(), impl->m_compositor, impl->m_displayGl, impl->m_emulationGl.get()); impl->m_postWorker.reset(postWorkerGl); impl->m_displaySurfaceUsers.push_back(postWorkerGl); @@ -1624,15 +1553,6 @@ FrameBuffer::Impl::~Impl() { } m_colorBufferDelayedCloseList.clear(); -#if GFXSTREAM_ENABLE_HOST_GLES - m_windows.clear(); - m_contexts.clear(); - - for (auto it : m_platformEglContexts) { - destroySharedTrivialContext(it.second.context, it.second.surface); - } -#endif - if (m_emulationGl) { m_emulationGl.reset(); } @@ -2058,13 +1978,13 @@ bool FrameBuffer::Impl::removeSubWindow_locked() { return removed; } -HandleType FrameBuffer::Impl::genHandle_locked() { +uint32_t FrameBuffer::Impl::genHandleLocked() NO_THREAD_SAFETY_ANALYSIS { HandleType id; do { id = ++sNextHandle; } while (id == 0 || #if GFXSTREAM_ENABLE_HOST_GLES - m_contexts.find(id) != m_contexts.end() || m_windows.find(id) != m_windows.end() || + (m_emulationGl && m_emulationGl->isHandleInUse(id)) || #endif m_colorbuffers.find(id) != m_colorbuffers.end() || m_buffers.find(id) != m_buffers.end()); @@ -2088,7 +2008,7 @@ HandleType FrameBuffer::Impl::createColorBuffer(int p_width, int p_height, Gfxst sweepColorBuffersLocked(); AutoLock colorBufferMapLock(m_colorBufferMapLock); - HandleType handle = genHandle_locked(); + HandleType handle = genHandleLocked(); if (!createColorBufferWithResourceHandleLocked(p_width, p_height, format, handle)) { GFXSTREAM_ERROR("Failed to create color buffer with resource handle"); return 0; @@ -2163,13 +2083,14 @@ bool FrameBuffer::Impl::createColorBufferWithResourceHandleLocked(int p_width, i // Explicitly set refcount to 1 to avoid the colorbuffer being added to // m_colorBufferDelayedCloseList in FrameBuffer::Impl::onLoad(). if (m_refCountPipeEnabled) { - m_colorbuffers.try_emplace(handle, ColorBufferRef{std::move(cb), 1, false, 0}); + m_colorbuffers.try_emplace(handle, ReferenceCountedColorBuffer{std::move(cb), 1, false, 0}); } else { const int apiLevel = get_gfxstream_guest_android_api_level(); // pre-O and post-O use different color buffer memory management // logic if (apiLevel > 0 && apiLevel < 26) { - m_colorbuffers.try_emplace(handle, ColorBufferRef{std::move(cb), 1, false, 0}); + m_colorbuffers.try_emplace(handle, + ReferenceCountedColorBuffer{std::move(cb), 1, false, 0}); RenderThreadInfo* tInfo = RenderThreadInfo::get(); uint64_t puid = tInfo->m_puid; @@ -2178,7 +2099,8 @@ bool FrameBuffer::Impl::createColorBufferWithResourceHandleLocked(int p_width, i } } else { - m_colorbuffers.try_emplace(handle, ColorBufferRef{std::move(cb), 0, false, 0}); + m_colorbuffers.try_emplace(handle, + ReferenceCountedColorBuffer{std::move(cb), 0, false, 0}); } } @@ -2188,7 +2110,7 @@ bool FrameBuffer::Impl::createColorBufferWithResourceHandleLocked(int p_width, i HandleType FrameBuffer::Impl::createBuffer(uint64_t p_size, uint32_t memoryProperty) { AutoLock mutex(m_lock); AutoLock colorBufferMapLock(m_colorBufferMapLock); - HandleType handle = genHandle_locked(); + HandleType handle = genHandleLocked(); if (!createBufferWithResourceHandleLocked(p_size, handle, memoryProperty)) { GFXSTREAM_ERROR("Failed to create buffer"); return 0; @@ -2230,10 +2152,9 @@ int FrameBuffer::Impl::openColorBuffer(HandleType p_colorbuffer) { AutoLock mutex(m_lock); - ColorBufferMap::iterator c; { AutoLock colorBuffermapLock(m_colorBufferMapLock); - c = m_colorbuffers.find(p_colorbuffer); + auto c = m_colorbuffers.find(p_colorbuffer); if (c == m_colorbuffers.end()) { // bad colorbuffer handle GFXSTREAM_ERROR("FB: openColorBuffer cb handle %d not found", p_colorbuffer); @@ -2305,7 +2226,7 @@ bool FrameBuffer::Impl::closeColorBufferLocked(HandleType p_colorbuffer, bool fo if (m_noDelayCloseColorBufferEnabled) forced = true; - ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer)); + auto c = m_colorbuffers.find(p_colorbuffer); if (c == m_colorbuffers.end()) { // This is harmless: it is normal for guest system to issue // closeColorBuffer command when the color buffer is already @@ -2340,7 +2261,7 @@ bool FrameBuffer::Impl::closeColorBufferLocked(HandleType p_colorbuffer, bool fo void FrameBuffer::Impl::decColorBufferRefCountNoDestroy(HandleType p_colorbuffer) { AutoLock colorBufferMapLock(m_colorBufferMapLock); - ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer)); + auto c = m_colorbuffers.find(p_colorbuffer); if (c == m_colorbuffers.end()) { return; } @@ -2460,7 +2381,8 @@ void FrameBuffer::Impl::cleanupProcGLObjects(uint64_t puid) { } } -std::vector FrameBuffer::Impl::cleanupProcGLObjects_locked(uint64_t puid, bool forced) { +std::vector FrameBuffer::Impl::cleanupProcGLObjects_locked(uint64_t puid, bool forced) + NO_THREAD_SAFETY_ANALYSIS { std::vector colorBuffersToCleanup; { std::unique_ptr bind = nullptr; @@ -2468,30 +2390,21 @@ std::vector FrameBuffer::Impl::cleanupProcGLObjects_locked(uint64_t if (m_emulationGl) { bind = std::make_unique(getPbufferSurfaceContextHelper()); } - // Clean up window surfaces + // Clean up GLES window surfaces and contexts if (m_emulationGl) { - auto procIte = m_procOwnedEmulatedEglWindowSurfaces.find(puid); - if (procIte != m_procOwnedEmulatedEglWindowSurfaces.end()) { - for (auto whndl : procIte->second) { - auto w = m_windows.find(whndl); - // TODO(b/265186226): figure out if we are leaking? - if (w == m_windows.end()) { - continue; - } - if (!m_guestManagedColorBufferLifetime) { - if (m_refCountPipeEnabled) { - if (decColorBufferRefCountLocked(w->second.second)) { - colorBuffersToCleanup.push_back(w->second.second); - } - } else { - if (closeColorBufferLocked(w->second.second, forced)) { - colorBuffersToCleanup.push_back(w->second.second); - } + auto colorBuffers = m_emulationGl->cleanupProcGLObjects(puid); + for (auto cb : colorBuffers) { + if (!m_guestManagedColorBufferLifetime) { + if (m_refCountPipeEnabled) { + if (decColorBufferRefCountLocked(cb)) { + colorBuffersToCleanup.push_back(cb); + } + } else { + if (closeColorBufferLocked(cb, forced)) { + colorBuffersToCleanup.push_back(cb); } } - m_windows.erase(w); } - m_procOwnedEmulatedEglWindowSurfaces.erase(procIte); } } #endif @@ -2513,39 +2426,12 @@ std::vector FrameBuffer::Impl::cleanupProcGLObjects_locked(uint64_t } } } - -#if GFXSTREAM_ENABLE_HOST_GLES - // Clean up EGLImage handles - if (m_emulationGl) { - auto procImagesIt = m_procOwnedEmulatedEglImages.find(puid); - if (procImagesIt != m_procOwnedEmulatedEglImages.end()) { - for (auto image : procImagesIt->second) { - m_images.erase(image); - } - m_procOwnedEmulatedEglImages.erase(procImagesIt); - } - } -#endif - } - -#if GFXSTREAM_ENABLE_HOST_GLES - // Unbind before cleaning up contexts - // Cleanup render contexts - if (m_emulationGl) { - auto procIte = m_procOwnedEmulatedEglContexts.find(puid); - if (procIte != m_procOwnedEmulatedEglContexts.end()) { - for (auto ctx : procIte->second) { - m_contexts.erase(ctx); - } - m_procOwnedEmulatedEglContexts.erase(procIte); - } } -#endif return colorBuffersToCleanup; } -void FrameBuffer::Impl::markOpened(ColorBufferRef* cbRef) { +void FrameBuffer::Impl::markOpened(ReferenceCountedColorBuffer* cbRef) { cbRef->opened = true; eraseDelayedCloseColorBufferLocked(cbRef->cb->getHndl(), cbRef->closedTs); cbRef->closedTs = 0; @@ -2571,7 +2457,7 @@ void FrameBuffer::Impl::readColorBuffer(HandleType p_colorbuffer, int x, int y, AutoLock mutex(m_lock); - ColorBufferPtr colorBuffer = findColorBuffer(p_colorbuffer); + IColorBufferRef colorBuffer = findColorBuffer(p_colorbuffer); if (!colorBuffer) { // bad colorbuffer handle return; @@ -2599,7 +2485,7 @@ void FrameBuffer::Impl::readColorBufferYUV(HandleType p_colorbuffer, int x, int int height, void* outPixels, uint32_t outPixelsSize) { AutoLock mutex(m_lock); - ColorBufferPtr colorBuffer = findColorBuffer(p_colorbuffer); + auto colorBuffer = findColorBuffer(p_colorbuffer); if (!colorBuffer) { // bad colorbuffer handle return; @@ -2632,15 +2518,13 @@ bool FrameBuffer::Impl::updateColorBuffer(HandleType p_colorbuffer, int x, int y AutoLock mutex(m_lock); - ColorBufferPtr colorBuffer = findColorBuffer(p_colorbuffer); + auto colorBuffer = findColorBuffer(p_colorbuffer); if (!colorBuffer) { // bad colorbuffer handle return false; } - colorBuffer->updateFromBytes(x, y, width, height, pixelsFormat, pixels); - - return true; + return colorBuffer->updateFromBytes(x, y, width, height, pixelsFormat, pixels); } bool FrameBuffer::Impl::updateColorBufferDeprecated(HandleType colorbuffer, int x, int y, int width, @@ -2713,7 +2597,7 @@ AsyncResult FrameBuffer::Impl::postImpl(HandleType p_colorbuffer, Post::Completi ColorBufferPtr colorBuffer = nullptr; { AutoLock colorBufferMapLock(m_colorBufferMapLock); - ColorBufferMap::iterator c = m_colorbuffers.find(p_colorbuffer); + auto c = m_colorbuffers.find(p_colorbuffer); if (c != m_colorbuffers.end()) { colorBuffer = c->second.cb; c->second.refcount++; @@ -2788,7 +2672,8 @@ AsyncResult FrameBuffer::Impl::postImpl(HandleType p_colorbuffer, Post::Completi continue; } - cb = findColorBuffer(displayColorBufferHandle); + cb = std::static_pointer_cast( + findColorBuffer(displayColorBufferHandle)); if (!cb) { GFXSTREAM_ERROR("Failed to find ColorBuffer %d, skip onPost", displayColorBufferHandle); @@ -2804,9 +2689,11 @@ AsyncResult FrameBuffer::Impl::postImpl(HandleType p_colorbuffer, Post::Completi doPostCallback(iter.second.img, iter.first); } } else { - #if GFXSTREAM_ENABLE_HOST_GLES - cb->glOpReadback(iter.second.img, iter.second.readBgra); - #endif + ensureReadbackWorker(); + if (m_readbackWorker) { + m_readbackWorker->doNextReadbackSync(cb.get(), iter.second.img, + iter.second.readBgra); + } doPostCallback(iter.second.img, iter.first); } } @@ -2972,7 +2859,7 @@ int FrameBuffer::Impl::getScreenshot(unsigned int nChannels, unsigned int* width if (displayId == 0) { cb = m_lastPostedColorBuffer; } - ColorBufferPtr colorBuffer = findColorBuffer(cb); + IColorBufferRef colorBuffer = findColorBuffer(cb); if (!colorBuffer) { *width = 0; *height = 0; @@ -3014,14 +2901,26 @@ int FrameBuffer::Impl::getScreenshot(unsigned int nChannels, unsigned int* width *height = screenHeight; } - int needed = - useSnipping ? (nChannels * rect.size.w * rect.size.h) : (nChannels * (*width) * (*height)); + // Clamp to something the GL/Vk backends can actually allocate, and + // compute the byte count in 64-bit so a hostile desiredWidth/Height + // (poisoned via rcSetDisplayPose + unauthenticated gRPC) cannot wrap + // `needed` and bypass the size check below. + constexpr unsigned int kMaxScreenshotDim = 1 << 16; + if (*width <= 0 || *width > kMaxScreenshotDim || + *height <= 0 || *height > kMaxScreenshotDim) { + *cPixels = 0; + return -1; + } + + const uint64_t needed64 = + useSnipping ? (uint64_t)nChannels * rect.size.w * rect.size.h + : (uint64_t)nChannels * (*width) * (*height); - if (*cPixels < (size_t)needed) { - *cPixels = needed; + if (needed64 > SIZE_MAX || *cPixels < (size_t)needed64) { + *cPixels = needed64; return Renderer::GET_SCREENSHOT_RESULT_PIXELS_SIZE; } - *cPixels = needed; + *cPixels = needed64; if (desiredRotation == GFXSTREAM_ROTATION_90 || desiredRotation == GFXSTREAM_ROTATION_270) { std::swap(*width, *height); std::swap(screenWidth, screenHeight); @@ -3073,7 +2972,7 @@ int FrameBuffer::Impl::getScreenshot(unsigned int nChannels, unsigned int* width } int FrameBuffer::Impl::getColorBufferScreenshot( - ColorBuffer* cb, int targetWidth, int targetHeight, int skinRotation, + IColorBuffer* cb, int targetWidth, int targetHeight, int skinRotation, GfxstreamFormat pixelsFormat, void* outPixels, const Rect& rect, const std::optional>& colorTransform) { uint8_t* outPixelsRGBA = reinterpret_cast(outPixels); @@ -3230,7 +3129,8 @@ AsyncResult FrameBuffer::Impl::composeWithCallback(uint32_t bufferSize, void* bu } } -void FrameBuffer::Impl::onSave(Stream* stream, const ITextureSaverPtr& textureSaver) { +bool FrameBuffer::Impl::onSave(Stream* stream, + const ITextureSaverPtr& textureSaver) NO_THREAD_SAFETY_ANALYSIS { // Things we do not need to snapshot: // m_eglSurface // m_eglContext @@ -3254,12 +3154,7 @@ void FrameBuffer::Impl::onSave(Stream* stream, const ITextureSaverPtr& textureSa // (textures created by the host are not saved!) // eglSaveAllImages labels all EGLImages (both host and guest) to be saved // and save all labeled textures and EGLImages. - if (s_egl.eglPreSaveContext && s_egl.eglSaveAllImages) { - for (const auto& ctx : m_contexts) { - s_egl.eglPreSaveContext(getDisplay(), ctx.second->getEGLContext(), stream); - } - s_egl.eglSaveAllImages(getDisplay(), stream, &textureSaver); - } + m_emulationGl->preSave(stream, textureSaver); } #endif @@ -3278,6 +3173,21 @@ void FrameBuffer::Impl::onSave(Stream* stream, const ITextureSaverPtr& textureSa s->putBe32(pair.second.dpiY); }); + // Save display ids created through createDisplay + std::vector displayIds; + int32_t currentId = -1; + uint32_t nextId; + while (get_gfxstream_multi_display_operations().get_next_display_info( + currentId, &nextId, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr)) { + displayIds.push_back(nextId); + currentId = nextId; + } + + stream->putBe32(displayIds.size()); + for (uint32_t id : displayIds) { + stream->putBe32(id); + } + stream->putBe32(m_useSubWindow); stream->putBe32(/*Obsolete m_eglContextInitialized =*/1); @@ -3292,9 +3202,9 @@ void FrameBuffer::Impl::onSave(Stream* stream, const ITextureSaverPtr& textureSa // objects). // TODO: skip reading from GPU even for texture objects. #if GFXSTREAM_ENABLE_HOST_GLES - saveCollection( - stream, m_contexts, - [](Stream* s, const EmulatedEglContextMap::value_type& pair) { pair.second->onSave(s); }); + if (m_emulationGl) { + m_emulationGl->saveContexts(stream); + } #endif // We don't need to save |m_colorBufferCloseTsMap| here - there's enough @@ -3304,30 +3214,33 @@ void FrameBuffer::Impl::onSave(Stream* stream, const ITextureSaverPtr& textureSa { AutoLock colorBufferMapLock(m_colorBufferMapLock); stream->putByte(m_guestManagedColorBufferLifetime); - saveCollection(stream, m_colorbuffers, - [now](Stream* s, const ColorBufferMap::value_type& pair) { - pair.second.cb->onSave(s); - s->putBe32(pair.second.refcount); - s->putByte(pair.second.opened); - s->putBe32(std::max(0, now - pair.second.closedTs)); - }); + saveCollection(stream, m_colorbuffers, [now](Stream* s, const auto& pair) { + auto cb = pair.second.cb; + assert(cb); + cb->onSave(s); + s->putBe32(pair.second.refcount); + s->putByte(pair.second.opened); + s->putBe32(std::max(0, now - pair.second.closedTs)); + }); } stream->putBe32(m_lastPostedColorBuffer); #if GFXSTREAM_ENABLE_HOST_GLES - saveCollection(stream, m_windows, - [](Stream* s, const EmulatedEglWindowSurfaceMap::value_type& pair) { - pair.second.first->onSave(s); - s->putBe32(pair.second.second); // Color buffer handle. - }); + if (m_emulationGl) { + m_emulationGl->saveWindowSurfaces(stream); + } #endif #if GFXSTREAM_ENABLE_HOST_GLES - saveProcOwnedCollection(stream, m_procOwnedEmulatedEglWindowSurfaces); + if (m_emulationGl) { + m_emulationGl->saveProcOwnedWindowSurfaces(stream); + } #endif saveProcOwnedCollection(stream, m_procOwnedColorBuffers); #if GFXSTREAM_ENABLE_HOST_GLES - saveProcOwnedCollection(stream, m_procOwnedEmulatedEglImages); - saveProcOwnedCollection(stream, m_procOwnedEmulatedEglContexts); + if (m_emulationGl) { + m_emulationGl->saveProcOwnedImages(stream); + m_emulationGl->saveProcOwnedContexts(stream); + } #endif // TODO(b/309858017): remove if when ready to bump snapshot version @@ -3342,28 +3255,23 @@ void FrameBuffer::Impl::onSave(Stream* stream, const ITextureSaverPtr& textureSa // Save Vulkan state if (m_features.VulkanSnapshots.enabled() && vk::VkDecoderGlobalState::get()) { - vk::VkDecoderGlobalState::get()->save(stream); + bool res = vk::VkDecoderGlobalState::get()->save(stream); + if (!res) { + return false; + } } #if GFXSTREAM_ENABLE_HOST_GLES if (m_emulationGl) { - if (s_egl.eglPostSaveContext) { - for (const auto& ctx : m_contexts) { - s_egl.eglPostSaveContext(getDisplay(), ctx.second->getEGLContext(), stream); - } - // We need to run the post save step for m_eglContext - // to mark their texture handles dirty - if (getContext() != EGL_NO_CONTEXT) { - s_egl.eglPostSaveContext(getDisplay(), getContext(), stream); - } - } - + m_emulationGl->postSave(stream); EmulatedEglFenceSync::onSave(stream); } #endif + return true; } -bool FrameBuffer::Impl::onLoad(Stream* stream, const ITextureLoaderPtr& textureLoader) { +bool FrameBuffer::Impl::onLoad(Stream* stream, + const ITextureLoaderPtr& textureLoader) NO_THREAD_SAFETY_ANALYSIS { AutoLock lock(m_lock); // cleanups { @@ -3385,19 +3293,19 @@ bool FrameBuffer::Impl::onLoad(Stream* stream, const ITextureLoaderPtr& textureL AutoLock colorBufferMapLock(m_colorBufferMapLock); if (m_procOwnedCleanupCallbacks.empty() && m_procOwnedColorBuffers.empty() && #if GFXSTREAM_ENABLE_HOST_GLES - m_procOwnedEmulatedEglContexts.empty() && m_procOwnedEmulatedEglImages.empty() && - m_procOwnedEmulatedEglWindowSurfaces.empty() && + (!m_emulationGl || !m_emulationGl->hasProcOwnedResources()) && #endif ( #if GFXSTREAM_ENABLE_HOST_GLES - !m_contexts.empty() || !m_windows.empty() || + (m_emulationGl && m_emulationGl->hasContextsOrWindowSurfaces()) || #endif m_colorbuffers.size() > m_colorBufferDelayedCloseList.size())) { // we are likely on a legacy system image, which does not have // process owned objects. We need to force cleanup everything #if GFXSTREAM_ENABLE_HOST_GLES - m_contexts.clear(); - m_windows.clear(); + if (m_emulationGl) { + m_emulationGl->clearContextsAndWindowSurfaces(); + } #endif m_colorbuffers.clear(); cleanupComplete = true; @@ -3407,11 +3315,13 @@ bool FrameBuffer::Impl::onLoad(Stream* stream, const ITextureLoaderPtr& textureL std::vector colorBuffersToCleanup; #if GFXSTREAM_ENABLE_HOST_GLES - while (m_procOwnedEmulatedEglWindowSurfaces.size()) { - auto cleanupHandles = cleanupProcGLObjects_locked( - m_procOwnedEmulatedEglWindowSurfaces.begin()->first, true); - colorBuffersToCleanup.insert(colorBuffersToCleanup.end(), cleanupHandles.begin(), - cleanupHandles.end()); + if (m_emulationGl) { + auto glPuids = m_emulationGl->getGLPUIDs(); + for (uint64_t puid : glPuids) { + auto cleanupHandles = cleanupProcGLObjects_locked(puid, true); + colorBuffersToCleanup.insert(colorBuffersToCleanup.end(), + cleanupHandles.begin(), cleanupHandles.end()); + } } #endif while (m_procOwnedColorBuffers.size()) { @@ -3420,20 +3330,6 @@ bool FrameBuffer::Impl::onLoad(Stream* stream, const ITextureLoaderPtr& textureL colorBuffersToCleanup.insert(colorBuffersToCleanup.end(), cleanupHandles.begin(), cleanupHandles.end()); } -#if GFXSTREAM_ENABLE_HOST_GLES - while (m_procOwnedEmulatedEglImages.size()) { - auto cleanupHandles = - cleanupProcGLObjects_locked(m_procOwnedEmulatedEglImages.begin()->first, true); - colorBuffersToCleanup.insert(colorBuffersToCleanup.end(), cleanupHandles.begin(), - cleanupHandles.end()); - } - while (m_procOwnedEmulatedEglContexts.size()) { - auto cleanupHandles = cleanupProcGLObjects_locked( - m_procOwnedEmulatedEglContexts.begin()->first, true); - colorBuffersToCleanup.insert(colorBuffersToCleanup.end(), cleanupHandles.begin(), - cleanupHandles.end()); - } -#endif std::vector> cleanupCallbacks; @@ -3465,8 +3361,9 @@ bool FrameBuffer::Impl::onLoad(Stream* stream, const ITextureLoaderPtr& textureL } m_colorBufferDelayedCloseList.clear(); #if GFXSTREAM_ENABLE_HOST_GLES - assert(m_contexts.empty()); - assert(m_windows.empty()); + if (m_emulationGl) { + assert(!m_emulationGl->hasContextsOrWindowSurfaces()); + } #endif { AutoLock colorBufferMapLock(m_colorBufferMapLock); @@ -3478,9 +3375,7 @@ bool FrameBuffer::Impl::onLoad(Stream* stream, const ITextureLoaderPtr& textureL } #if GFXSTREAM_ENABLE_HOST_GLES if (m_emulationGl) { - if (s_egl.eglLoadAllImages) { - s_egl.eglLoadAllImages(getDisplay(), stream, &textureLoader); - } + m_emulationGl->loadAllImages(stream, textureLoader); } #endif } @@ -3499,6 +3394,12 @@ bool FrameBuffer::Impl::onLoad(Stream* stream, const ITextureLoaderPtr& textureL return {idx, {w, h, dpiX, dpiY}}; }); + uint32_t numDisplays = stream->getBe32(); + for (uint32_t i = 0; i < numDisplays; ++i) { + uint32_t displayId = stream->getBe32(); + get_gfxstream_multi_display_operations().create_display(&displayId); + } + // TODO: resize the window // m_useSubWindow = stream->getBe32(); @@ -3509,15 +3410,12 @@ bool FrameBuffer::Impl::onLoad(Stream* stream, const ITextureLoaderPtr& textureL m_statsStartTime = stream->getBe64(); #if GFXSTREAM_ENABLE_HOST_GLES - loadCollection( - stream, &m_contexts, [this](Stream* stream) -> EmulatedEglContextMap::value_type { - ENSURE_GL_EMULATION_FATAL(); - - auto context = m_emulationGl->loadEmulatedEglContext(stream); - auto contextHandle = context ? context->getHndl() : 0; - return {contextHandle, std::move(context)}; - }); - assert(!gfxstream::base::find(m_contexts, 0)); + if (m_emulationGl) { + if (!m_emulationGl->loadContexts(stream)) { + GFXSTREAM_ERROR("Failed to load GL contexts."); + return false; + } + } #endif auto now = gfxstream::base::getUnixTimeUs(); @@ -3525,7 +3423,8 @@ bool FrameBuffer::Impl::onLoad(Stream* stream, const ITextureLoaderPtr& textureL AutoLock colorBufferMapLock(m_colorBufferMapLock); m_guestManagedColorBufferLifetime = stream->getByte(); loadCollection( - stream, &m_colorbuffers, [this, now](Stream* stream) -> ColorBufferMap::value_type { + stream, &m_colorbuffers, + [this, now](Stream* stream) -> std::pair { ColorBufferPtr cb = ColorBuffer::onLoad(m_emulationGl.get(), m_emulationVk.get(), stream); if (!cb) { @@ -3538,7 +3437,8 @@ bool FrameBuffer::Impl::onLoad(Stream* stream, const ITextureLoaderPtr& textureL if (refCount == 0) { m_colorBufferDelayedCloseList.push_back({closedTs, handle}); } - return {handle, ColorBufferRef{std::move(cb), refCount, opened, closedTs}}; + return {handle, + ReferenceCountedColorBuffer{std::move(cb), refCount, opened, closedTs}}; }); } m_lastPostedColorBuffer = static_cast(stream->getBe32()); @@ -3547,26 +3447,32 @@ bool FrameBuffer::Impl::onLoad(Stream* stream, const ITextureLoaderPtr& textureL { AutoLock colorBufferMapLock(m_colorBufferMapLock); #if GFXSTREAM_ENABLE_HOST_GLES - loadCollection( - stream, &m_windows, [this](Stream* stream) -> EmulatedEglWindowSurfaceMap::value_type { - ENSURE_GL_EMULATION_FATAL(); - auto window = - m_emulationGl->loadEmulatedEglWindowSurface(stream, m_colorbuffers, m_contexts); - - HandleType handle = window->getHndl(); - HandleType colorBufferHandle = stream->getBe32(); - return {handle, {std::move(window), colorBufferHandle}}; - }); + if (m_emulationGl) { + if (!m_emulationGl->loadWindowSurfaces(stream, + [this](uint32_t handle) -> IColorBufferRef { + auto it = m_colorbuffers.find(handle); + if (it == m_colorbuffers.end()) + return nullptr; + return it->second.cb; + })) { + GFXSTREAM_ERROR("Failed to load GL window surfaces."); + return false; + } + } #endif } #if GFXSTREAM_ENABLE_HOST_GLES - loadProcOwnedCollection(stream, &m_procOwnedEmulatedEglWindowSurfaces); + if (m_emulationGl) { + m_emulationGl->loadProcOwnedWindowSurfaces(stream); + } #endif loadProcOwnedCollection(stream, &m_procOwnedColorBuffers); #if GFXSTREAM_ENABLE_HOST_GLES - loadProcOwnedCollection(stream, &m_procOwnedEmulatedEglImages); - loadProcOwnedCollection(stream, &m_procOwnedEmulatedEglContexts); + if (m_emulationGl) { + m_emulationGl->loadProcOwnedImages(stream); + m_emulationGl->loadProcOwnedContexts(stream); + } #endif // TODO(b/309858017): remove if when ready to bump snapshot version if (m_features.VulkanSnapshots.enabled()) { @@ -3585,9 +3491,7 @@ bool FrameBuffer::Impl::onLoad(Stream* stream, const ITextureLoaderPtr& textureL #if GFXSTREAM_ENABLE_HOST_GLES if (m_emulationGl) { - if (s_egl.eglPostLoadAllImages) { - s_egl.eglPostLoadAllImages(getDisplay(), stream); - } + m_emulationGl->postLoad(stream); } registerTriggerWait(); @@ -3637,24 +3541,50 @@ void FrameBuffer::Impl::lock() { m_lock.lock(); } void FrameBuffer::Impl::unlock() { m_lock.unlock(); } -ColorBufferPtr FrameBuffer::Impl::findColorBuffer(HandleType p_colorbuffer) { +gfxstream::base::Lock& FrameBuffer::Impl::getGlobalLock() { return m_lock; } + +void FrameBuffer::Impl::lockGlobalState() { lock(); } + +void FrameBuffer::Impl::unlockGlobalState() { unlock(); } + +IColorBufferRef FrameBuffer::Impl::findColorBuffer(HandleType p_colorbuffer) { AutoLock colorBufferMapLock(m_colorBufferMapLock); - ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer)); - if (c == m_colorbuffers.end()) { + auto it = m_colorbuffers.find(p_colorbuffer); + if (it == m_colorbuffers.end()) { return nullptr; - } else { - return c->second.cb; } + return std::dynamic_pointer_cast(it->second.cb); +} + +void FrameBuffer::Impl::openColorBufferByWindow(uint32_t colorBufferHandle) { + AutoLock colorBufferMapLock(m_colorBufferMapLock); + auto c = m_colorbuffers.find(colorBufferHandle); + if (c != m_colorbuffers.end()) { + markOpened(&c->second); + if (!m_guestManagedColorBufferLifetime) { + c->second.refcount++; + } + } +} + +bool FrameBuffer::Impl::closeColorBufferByWindow(uint32_t colorBufferHandle) { + if (!m_guestManagedColorBufferLifetime) { + if (m_refCountPipeEnabled) { + return decColorBufferRefCountLocked(colorBufferHandle); + } else { + return closeColorBufferLocked(colorBufferHandle); + } + } + return false; } BufferPtr FrameBuffer::Impl::findBuffer(HandleType p_buffer) { AutoLock colorBufferMapLock(m_colorBufferMapLock); - BufferMap::iterator b(m_buffers.find(p_buffer)); - if (b == m_buffers.end()) { + auto it = m_buffers.find(p_buffer); + if (it == m_buffers.end()) { return nullptr; - } else { - return b->second.buffer; } + return it->second.buffer; } void FrameBuffer::Impl::registerProcessCleanupCallback(void* key, uint64_t contextId, @@ -3682,6 +3612,32 @@ void FrameBuffer::Impl::unregisterProcessCleanupCallback(void* key) { } } +void FrameBuffer::Impl::invalidateColorBuffer(uint32_t colorBufferHandle) { + invalidateColorBufferForVk(colorBufferHandle); +} + +void FrameBuffer::Impl::flushColorBuffer(uint32_t colorBufferHandle) { + flushColorBufferFromVk(colorBufferHandle); +} + +void FrameBuffer::Impl::flushColorBufferFromBytes(uint32_t colorBufferHandle, const void* bytes, + size_t bytesSize) { + flushColorBufferFromVkBytes(colorBufferHandle, bytes, bytesSize); +} + +CancelableFuture FrameBuffer::Impl::scheduleAsyncWork(std::function work, + std::string_view description) { + auto promise = std::make_shared(); + auto future = promise->GetFuture(); + SyncThread::get()->triggerGeneral( + [promise = std::move(promise), work = std::move(work)]() mutable { + work(); + promise->MarkComplete(); + }, + std::string(description)); + return future; +} + const ProcessResources* FrameBuffer::Impl::getProcessResources(uint64_t puid) { { AutoLock mutex(m_procOwnedResourcesLock); @@ -3778,48 +3734,6 @@ void FrameBuffer::Impl::setGuestManagedColorBufferLifetime(bool guestManaged) { m_guestManagedColorBufferLifetime = guestManaged; } -std::unique_ptr FrameBuffer::Impl::borrowColorBufferForComposition( - uint32_t colorBufferHandle, bool colorBufferIsTarget) { - ColorBufferPtr colorBufferPtr = findColorBuffer(colorBufferHandle); - if (!colorBufferPtr) { - GFXSTREAM_ERROR("Failed to get borrowed image info for ColorBuffer:%d", colorBufferHandle); - return nullptr; - } - - if (m_useVulkanComposition) { - invalidateColorBufferForVk(colorBufferHandle); - } else { -#if GFXSTREAM_ENABLE_HOST_GLES - invalidateColorBufferForGl(colorBufferHandle); -#endif - } - - const auto api = m_useVulkanComposition ? ColorBuffer::UsedApi::kVk : ColorBuffer::UsedApi::kGl; - return colorBufferPtr->borrowForComposition(api, colorBufferIsTarget); -} - -std::unique_ptr FrameBuffer::Impl::borrowColorBufferForDisplay( - uint32_t colorBufferHandle) { - ColorBufferPtr colorBufferPtr = findColorBuffer(colorBufferHandle); - if (!colorBufferPtr) { - GFXSTREAM_ERROR("Failed to get borrowed image info for ColorBuffer:%d", colorBufferHandle); - return nullptr; - } - - if (m_useVulkanComposition) { - invalidateColorBufferForVk(colorBufferHandle); - } else { -#if GFXSTREAM_ENABLE_HOST_GLES - invalidateColorBufferForGl(colorBufferHandle); -#else - GFXSTREAM_ERROR("Failed to invalidate ColorBuffer:%d", colorBufferHandle); -#endif - } - - const auto api = m_useVulkanComposition ? ColorBuffer::UsedApi::kVk : ColorBuffer::UsedApi::kGl; - return colorBufferPtr->borrowForDisplay(api); -} - void FrameBuffer::Impl::logVulkanDeviceLost() { if (!m_emulationVk) { GFXSTREAM_FATAL("Device lost without VkEmulation?"); @@ -3904,7 +3818,8 @@ int FrameBuffer::Impl::getDisplayActiveConfig() { bool FrameBuffer::Impl::flushColorBufferFromVk(HandleType colorBufferHandle) { AutoLock mutex(m_lock); - auto colorBuffer = findColorBuffer(colorBufferHandle); + ColorBufferPtr colorBuffer = + std::static_pointer_cast(findColorBuffer(colorBufferHandle)); if (!colorBuffer) { GFXSTREAM_ERROR("%s: Failed to find ColorBuffer:%d", __func__, colorBufferHandle); return false; @@ -3916,7 +3831,8 @@ bool FrameBuffer::Impl::flushColorBufferFromVkBytes(HandleType colorBufferHandle size_t bytesSize) { AutoLock mutex(m_lock); - auto colorBuffer = findColorBuffer(colorBufferHandle); + ColorBufferPtr colorBuffer = + std::static_pointer_cast(findColorBuffer(colorBufferHandle)); if (!colorBuffer) { GFXSTREAM_ERROR("%s: Failed to find ColorBuffer:%d", __func__, colorBufferHandle); return false; @@ -3936,14 +3852,14 @@ bool FrameBuffer::Impl::invalidateColorBufferForVk(HandleType colorBufferHandle) GFXSTREAM_ERROR("Failed to find ColorBuffer: %d", colorBufferHandle); return false; } - return colorBuffer->invalidateForVk(); + return colorBuffer->invalidateForBackend(Backend::VK); } std::optional FrameBuffer::Impl::exportColorBuffer( HandleType colorBufferHandle) { AutoLock mutex(m_lock); - ColorBufferPtr colorBuffer = findColorBuffer(colorBufferHandle); + auto colorBuffer = findColorBuffer(colorBufferHandle); if (!colorBuffer) { return std::nullopt; } @@ -3982,15 +3898,11 @@ int32_t FrameBuffer::Impl::mapGpaToBufferHandle(uint32_t bufferHandle, uint64_t } #if GFXSTREAM_ENABLE_HOST_GLES -HandleType FrameBuffer::Impl::getEmulatedEglWindowSurfaceColorBufferHandle(HandleType p_surface) { +HandleType FrameBuffer::Impl::getEmulatedEglWindowSurfaceColorBufferHandle(HandleType p_surface) + NO_THREAD_SAFETY_ANALYSIS { + ENSURE_GL_EMULATION_VALUE(0); AutoLock mutex(m_lock); - - auto it = m_EmulatedEglWindowSurfaceToColorBuffer.find(p_surface); - if (it == m_EmulatedEglWindowSurfaceToColorBuffer.end()) { - return 0; - } - - return it->second; + return m_emulationGl->getWindowSurfaceColorBufferHandle(p_surface); } void FrameBuffer::Impl::setScreenMask(int width, int height, const uint8_t* rgbaData) { @@ -4042,7 +3954,7 @@ void FrameBuffer::Impl::setDisplayLayout(int screenWidth, int screenHeight, } #ifdef CONFIG_AEMU -void FrameBuffer::Impl::registerVulkanInstance(uint64_t id, const char* appName) const { +void FrameBuffer::Impl::registerVulkanInstance(uint64_t id, std::string_view appName) const { auto* tInfo = RenderThreadInfo::get(); std::string process_name; if (tInfo && tInfo->m_processName.has_value()) { @@ -4062,113 +3974,63 @@ void FrameBuffer::Impl::registerVulkanInstance(uint64_t id, const char* appName) void FrameBuffer::Impl::unregisterVulkanInstance(uint64_t id) const { get_gfxstream_vm_operations().unregister_vulkan_instance(id); } +#else +void FrameBuffer::Impl::registerVulkanInstance(uint64_t /*id*/, + std::string_view /*appName*/) const {} +void FrameBuffer::Impl::unregisterVulkanInstance(uint64_t /*id*/) const {} #endif void FrameBuffer::Impl::createTrivialContext(HandleType shared, HandleType* contextOut, - HandleType* surfOut) { - assert(contextOut); - assert(surfOut); - - *contextOut = createEmulatedEglContext(0, shared, GLESApi_2); - // Zero size is formally allowed here, but SwiftShader doesn't like it and - // fails. - *surfOut = createEmulatedEglWindowSurface(0, 1, 1); + HandleType* surfOut) NO_THREAD_SAFETY_ANALYSIS { + AutoLock mutex(m_lock); + if (m_emulationGl) { + m_emulationGl->createTrivialContext(shared, contextOut, surfOut); + } } -void FrameBuffer::Impl::createSharedTrivialContext(EGLContext* contextOut, EGLSurface* surfOut) { - assert(contextOut); - assert(surfOut); - - ENSURE_GL_EMULATION_VOID(); - - if (m_emulationGl->mEglConfig == EGL_NO_CONFIG) { - GFXSTREAM_FATAL("GL/EGL emulation has not chosen a config."); +void FrameBuffer::Impl::createSharedTrivialContext(EGLContext* contextOut, + EGLSurface* surfOut) NO_THREAD_SAFETY_ANALYSIS { + AutoLock mutex(m_lock); + if (m_emulationGl) { + m_emulationGl->createSharedTrivialContext(contextOut, surfOut); } +} - int maj, min; - get_gfxstream_gles_version(&maj, &min); +void FrameBuffer::Impl::destroySharedTrivialContext(EGLContext context, + EGLSurface surface) NO_THREAD_SAFETY_ANALYSIS { + AutoLock mutex(m_lock); + if (m_emulationGl) { + m_emulationGl->destroySharedTrivialContext(context, surface); + } +} - const EGLint contextAttribs[] = {EGL_CONTEXT_MAJOR_VERSION_KHR, maj, - EGL_CONTEXT_MINOR_VERSION_KHR, min, EGL_NONE}; +bool FrameBuffer::Impl::setEmulatedEglWindowSurfaceColorBuffer( + HandleType p_surface, HandleType p_colorbuffer) NO_THREAD_SAFETY_ANALYSIS { + ENSURE_GL_EMULATION_VALUE(false); + AutoLock mutex(m_lock); + return m_emulationGl->setEmulatedEglWindowSurfaceColorBuffer(p_surface, p_colorbuffer); +} - *contextOut = s_egl.eglCreateContext(getDisplay(), m_emulationGl->mEglConfig, - getGlobalEGLContext(), contextAttribs); +std::string FrameBuffer::Impl::getEglString(EGLenum name) { + ENSURE_GL_EMULATION_VALUE(""); + return m_emulationGl->getEglString(name); +} - const EGLint pbufAttribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE}; +std::string FrameBuffer::Impl::getGlString(EGLenum name) { + ENSURE_GL_EMULATION_VALUE(""); + return m_emulationGl->getGlString(name); +} - *surfOut = s_egl.eglCreatePbufferSurface(getDisplay(), m_emulationGl->mEglConfig, pbufAttribs); +GLESDispatchMaxVersion FrameBuffer::Impl::getMaxGlesVersion() { + ENSURE_GL_EMULATION_VALUE(GLES_DISPATCH_MAX_VERSION_2); + return m_emulationGl->getGlesMaxDispatchVersion(); } -void FrameBuffer::Impl::destroySharedTrivialContext(EGLContext context, EGLSurface surface) { - if (getDisplay() != EGL_NO_DISPLAY) { - s_egl.eglDestroyContext(getDisplay(), context); - s_egl.eglDestroySurface(getDisplay(), surface); +std::string FrameBuffer::Impl::getGlesExtensionsString() const { + if (!m_emulationGl) { + return ""; } -} - -bool FrameBuffer::Impl::setEmulatedEglWindowSurfaceColorBuffer(HandleType p_surface, - HandleType p_colorbuffer) { - AutoLock mutex(m_lock); - - EmulatedEglWindowSurfaceMap::iterator w(m_windows.find(p_surface)); - if (w == m_windows.end()) { - // bad surface handle - GFXSTREAM_ERROR("bad window surface handle %#x", p_surface); - return false; - } - - { - AutoLock colorBufferMapLock(m_colorBufferMapLock); - ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer)); - if (c == m_colorbuffers.end()) { - GFXSTREAM_ERROR("bad color buffer handle %d", p_colorbuffer); - // bad colorbuffer handle - return false; - } - - (*w).second.first->setColorBuffer((*c).second.cb); - markOpened(&c->second); - if (!m_guestManagedColorBufferLifetime) { - c->second.refcount++; - } - } - if (w->second.second) { - if (!m_guestManagedColorBufferLifetime) { - if (m_refCountPipeEnabled) { - decColorBufferRefCountLocked(w->second.second); - } else { - closeColorBufferLocked(w->second.second); - } - } - } - - (*w).second.second = p_colorbuffer; - - m_EmulatedEglWindowSurfaceToColorBuffer[p_surface] = p_colorbuffer; - - return true; -} - -std::string FrameBuffer::Impl::getEglString(EGLenum name) { - ENSURE_GL_EMULATION_VALUE(""); - return m_emulationGl->getEglString(name); -} - -std::string FrameBuffer::Impl::getGlString(EGLenum name) { - ENSURE_GL_EMULATION_VALUE(""); - return m_emulationGl->getGlString(name); -} - -GLESDispatchMaxVersion FrameBuffer::Impl::getMaxGlesVersion() { - ENSURE_GL_EMULATION_VALUE(GLES_DISPATCH_MAX_VERSION_2); - return m_emulationGl->getGlesMaxDispatchVersion(); -} - -std::string FrameBuffer::Impl::getGlesExtensionsString() const { - if (!m_emulationGl) { - return ""; - } - return m_emulationGl->getGlesExtensionsString(); + return m_emulationGl->getGlesExtensionsString(); } EGLint FrameBuffer::Impl::getEglVersion(EGLint* major, EGLint* minor) { @@ -4193,107 +4055,30 @@ EGLint FrameBuffer::Impl::chooseConfig(EGLint* attribs, EGLint* configs, EGLint } HandleType FrameBuffer::Impl::createEmulatedEglContext(int config, HandleType shareContextHandle, - GLESApi version) { + GLESApi version) NO_THREAD_SAFETY_ANALYSIS { ENSURE_GL_EMULATION_VALUE(0); AutoLock mutex(m_lock); - gfxstream::base::AutoWriteLock contextLock(m_contextStructureLock); - // Hold the ColorBuffer map lock so that the new handle won't collide with a ColorBuffer handle. AutoLock colorBufferMapLock(m_colorBufferMapLock); - EmulatedEglContextPtr shareContext = nullptr; - if (shareContextHandle != 0) { - auto shareContextIt = m_contexts.find(shareContextHandle); - if (shareContextIt == m_contexts.end()) { - GFXSTREAM_ERROR("Failed to find share EmulatedEglContext:%d", shareContextHandle); - return 0; - } - shareContext = shareContextIt->second; - } - - HandleType contextHandle = genHandle_locked(); - auto context = - m_emulationGl->createEmulatedEglContext(config, shareContext.get(), version, contextHandle); - if (!context) { - GFXSTREAM_ERROR("Failed to create EmulatedEglContext."); - return 0; - } - - m_contexts[contextHandle] = std::move(context); - - RenderThreadInfo* tinfo = RenderThreadInfo::get(); - uint64_t puid = tinfo->m_puid; - // The new emulator manages render contexts per guest process. - // Fall back to per-thread management if the system image does not - // support it. - if (puid) { - m_procOwnedEmulatedEglContexts[puid].insert(contextHandle); - } else { // legacy path to manage context lifetime by threads - if (!tinfo->m_glInfo) { - GFXSTREAM_ERROR("RenderThreadGL not available."); - } - else { - tinfo->m_glInfo->m_contextSet.insert(contextHandle); - } - } - - return contextHandle; + return m_emulationGl->createEmulatedEglContext(config, shareContextHandle, version); } -void FrameBuffer::Impl::destroyEmulatedEglContext(HandleType contextHandle) { +void FrameBuffer::Impl::destroyEmulatedEglContext(HandleType contextHandle) + NO_THREAD_SAFETY_ANALYSIS { + ENSURE_GL_EMULATION_VOID(); AutoLock mutex(m_lock); sweepColorBuffersLocked(); - gfxstream::base::AutoWriteLock contextLock(m_contextStructureLock); - m_contexts.erase(contextHandle); - RenderThreadInfo* tinfo = RenderThreadInfo::get(); - uint64_t puid = tinfo->m_puid; - // The new emulator manages render contexts per guest process. - // Fall back to per-thread management if the system image does not - // support it. - if (puid) { - auto it = m_procOwnedEmulatedEglContexts.find(puid); - if (it != m_procOwnedEmulatedEglContexts.end()) { - it->second.erase(contextHandle); - } - } else { - if (!tinfo->m_glInfo) { - GFXSTREAM_FATAL("RenderThreadGL not available."); - } - tinfo->m_glInfo->m_contextSet.erase(contextHandle); - } + m_emulationGl->destroyEmulatedEglContext(contextHandle); } -HandleType FrameBuffer::Impl::createEmulatedEglWindowSurface(int p_config, int p_width, - int p_height) { +HandleType FrameBuffer::Impl::createEmulatedEglWindowSurface( + int p_config, int p_width, int p_height) NO_THREAD_SAFETY_ANALYSIS { ENSURE_GL_EMULATION_VALUE(0); AutoLock mutex(m_lock); - // Hold the ColorBuffer map lock so that the new handle won't collide with a ColorBuffer handle. AutoLock colorBufferMapLock(m_colorBufferMapLock); - HandleType handle = genHandle_locked(); - - auto window = - m_emulationGl->createEmulatedEglWindowSurface(p_config, p_width, p_height, handle); - if (!window) { - GFXSTREAM_ERROR("Failed to create EmulatedEglWindowSurface."); - return 0; - } - - m_windows[handle] = {std::move(window), 0}; - - RenderThreadInfo* info = RenderThreadInfo::get(); - if (!info->m_glInfo) { - GFXSTREAM_FATAL("RRenderThreadInfoGl not available."); - } - - uint64_t puid = info->m_puid; - if (puid) { - m_procOwnedEmulatedEglWindowSurfaces[puid].insert(handle); - } else { // legacy path to manage window surface lifetime by threads - info->m_glInfo->m_windowSet.insert(handle); - } - - return handle; + return m_emulationGl->createEmulatedEglWindowSurface(p_config, p_width, p_height); } void FrameBuffer::Impl::destroyEmulatedEglWindowSurface(HandleType p_surface) { @@ -4305,36 +4090,21 @@ void FrameBuffer::Impl::destroyEmulatedEglWindowSurface(HandleType p_surface) { } std::vector FrameBuffer::Impl::destroyEmulatedEglWindowSurfaceLocked( - HandleType p_surface) { + HandleType p_surface) NO_THREAD_SAFETY_ANALYSIS { std::vector colorBuffersToCleanUp; - const auto w = m_windows.find(p_surface); - if (w != m_windows.end()) { - RecursiveScopedContextBind bind(getPbufferSurfaceContextHelper()); + auto colorBuffers = m_emulationGl->destroyEmulatedEglWindowSurface(p_surface); + for (auto cb : colorBuffers) { if (!m_guestManagedColorBufferLifetime) { if (m_refCountPipeEnabled) { - if (decColorBufferRefCountLocked(w->second.second)) { - colorBuffersToCleanUp.push_back(w->second.second); + if (decColorBufferRefCountLocked(cb)) { + colorBuffersToCleanUp.push_back(cb); } } else { - if (closeColorBufferLocked(w->second.second)) { - colorBuffersToCleanUp.push_back(w->second.second); + if (closeColorBufferLocked(cb)) { + colorBuffersToCleanUp.push_back(cb); } } } - m_windows.erase(w); - RenderThreadInfo* tinfo = RenderThreadInfo::get(); - uint64_t puid = tinfo->m_puid; - if (puid) { - auto ite = m_procOwnedEmulatedEglWindowSurfaces.find(puid); - if (ite != m_procOwnedEmulatedEglWindowSurfaces.end()) { - ite->second.erase(p_surface); - } - } else { - if (!tinfo->m_glInfo) { - GFXSTREAM_FATAL("RenderThreadGL not available."); - } - tinfo->m_glInfo->m_windowSet.erase(p_surface); - } } return colorBuffersToCleanUp; } @@ -4349,49 +4119,20 @@ void FrameBuffer::Impl::createEmulatedEglFenceSync(EGLenum type, int destroyWhen } if (m_emulationGl) { - // TODO(b/233939967): move RenderThreadInfoGl usage to EmulationGl. - RenderThreadInfoGl* const info = RenderThreadInfoGl::get(); - if (!info) { - GFXSTREAM_FATAL("RenderThreadGL not available."); - } - if (!info->currContext) { - uint32_t syncContext; - uint32_t syncSurface; - createTrivialContext(0, // There is no context to share. - &syncContext, &syncSurface); - bindContext(syncContext, syncSurface, syncSurface); - // This context is then cleaned up when the render thread exits. + if (outSync) { + *outSync = m_emulationGl->createEmulatedEglFenceSync(type, destroyWhenSignaled); } - - auto sync = m_emulationGl->createEmulatedEglFenceSync(type, destroyWhenSignaled); - if (sync && outSync) { - *outSync = (uint64_t)(uintptr_t)sync.release(); - } - } - else if (m_emulationVk) { + } else if (m_emulationVk) { // No-op: compose operations using this callback will be waited on the futures // generated before processing later rc commands. This ensures CPU and GPU // synchronization is established for non-async compose scenarios, where this // codepath is used via HostFrameComposer on non-virtiogpu/minigbm images. // Egl fences are not used on newer images with virtiogpu/minigbm. - } - else { + } else { GFXSTREAM_FATAL("Unimplemented"); } } -void FrameBuffer::Impl::postLoadRenderThreadContextSurfacePtrs() { - RenderThreadInfoGl* const info = RenderThreadInfoGl::get(); - if (!info) { - GFXSTREAM_FATAL("RenderThreadGL not available."); - } - - AutoLock lock(m_lock); - info->currContext = getContext_locked(info->currContextHandleFromLoad); - info->currDrawSurf = getWindowSurface_locked(info->currDrawSurfHandleFromLoad); - info->currReadSurf = getWindowSurface_locked(info->currReadSurfHandleFromLoad); -} - void FrameBuffer::Impl::drainGlRenderThreadResources() { // If we're already exiting then snapshot should not contain // this thread information at all. @@ -4399,77 +4140,31 @@ void FrameBuffer::Impl::drainGlRenderThreadResources() { return; } - // Release references to the current thread's context/surfaces if any - bindContext(0, 0, 0); - - drainGlRenderThreadSurfaces(); - drainGlRenderThreadContexts(); - - if (!s_egl.eglReleaseThread()) { - GFXSTREAM_ERROR("Error: RenderThread @%p failed to eglReleaseThread()", this); + if (m_emulationGl) { + m_emulationGl->drainRenderThreadResources(); } } -void FrameBuffer::Impl::drainGlRenderThreadContexts() { +void FrameBuffer::Impl::drainGlRenderThreadContexts() NO_THREAD_SAFETY_ANALYSIS { if (isShuttingDown()) { return; } - RenderThreadInfoGl* const tinfo = RenderThreadInfoGl::get(); - if (!tinfo) { - GFXSTREAM_FATAL("RenderThreadGL not available."); - } - - if (tinfo->m_contextSet.empty()) { - return; - } - AutoLock mutex(m_lock); - gfxstream::base::AutoWriteLock contextLock(m_contextStructureLock); - for (const HandleType contextHandle : tinfo->m_contextSet) { - m_contexts.erase(contextHandle); + if (m_emulationGl) { + m_emulationGl->drainRenderThreadContexts(); } - tinfo->m_contextSet.clear(); } -void FrameBuffer::Impl::drainGlRenderThreadSurfaces() { +void FrameBuffer::Impl::drainGlRenderThreadSurfaces() NO_THREAD_SAFETY_ANALYSIS { if (isShuttingDown()) { return; } - RenderThreadInfoGl* const tinfo = RenderThreadInfoGl::get(); - if (!tinfo) { - GFXSTREAM_FATAL("RenderThreadGL not available."); - } - - if (tinfo->m_windowSet.empty()) { - return; - } - - std::vector colorBuffersToCleanup; - AutoLock mutex(m_lock); - RecursiveScopedContextBind bind(getPbufferSurfaceContextHelper()); - for (const HandleType winHandle : tinfo->m_windowSet) { - const auto winIt = m_windows.find(winHandle); - if (winIt != m_windows.end()) { - if (const HandleType oldColorBufferHandle = winIt->second.second) { - if (!m_guestManagedColorBufferLifetime) { - if (m_refCountPipeEnabled) { - if (decColorBufferRefCountLocked(oldColorBufferHandle)) { - colorBuffersToCleanup.push_back(oldColorBufferHandle); - } - } else { - if (closeColorBufferLocked(oldColorBufferHandle)) { - colorBuffersToCleanup.push_back(oldColorBufferHandle); - } - } - } - m_windows.erase(winIt); - } - } + if (m_emulationGl) { + m_emulationGl->drainRenderThreadSurfaces(); } - tinfo->m_windowSet.clear(); } EmulationGl& FrameBuffer::Impl::getEmulationGl() { @@ -4477,6 +4172,8 @@ EmulationGl& FrameBuffer::Impl::getEmulationGl() { return *m_emulationGl; } +gl::EmulationGl* FrameBuffer::Impl::getEmulationGlPtr() { return m_emulationGl.get(); } + VkEmulation& FrameBuffer::Impl::getEmulationVk() { if (!m_emulationVk) { GFXSTREAM_FATAL("Vulkan emulation is not enabled."); @@ -4484,56 +4181,19 @@ VkEmulation& FrameBuffer::Impl::getEmulationVk() { return *m_emulationVk; } -EGLDisplay FrameBuffer::Impl::getDisplay() const { - ENSURE_GL_EMULATION_VALUE(nullptr); - return m_emulationGl->mEglDisplay; -} - -EGLSurface FrameBuffer::Impl::getWindowSurface() const { - ENSURE_GL_EMULATION_VALUE(0); - if (!m_emulationGl->mWindowSurface) { - return EGL_NO_SURFACE; - } - - const auto* displaySurfaceGl = - reinterpret_cast(m_emulationGl->mWindowSurface->getImpl()); - - return displaySurfaceGl->getSurface(); -} - -EGLContext FrameBuffer::Impl::getContext() const { - ENSURE_GL_EMULATION_VALUE(0); - return m_emulationGl->mEglContext; -} - -EGLContext FrameBuffer::Impl::getConfig() const { - ENSURE_GL_EMULATION_VALUE(nullptr); - return m_emulationGl->mEglConfig; +bool FrameBuffer::Impl::getRenderOpt(RenderOpt* opt) const { + ENSURE_GL_EMULATION_VALUE(false); + return m_emulationGl->getRenderOpt(opt); } EGLContext FrameBuffer::Impl::getGlobalEGLContext() const { ENSURE_GL_EMULATION_VALUE(0); - if (!m_emulationGl->mPbufferSurface) { - GFXSTREAM_FATAL("FrameBuffer pbuffer surface not available."); - } - - const auto* displaySurfaceGl = - reinterpret_cast(m_emulationGl->mPbufferSurface->getImpl()); - - return displaySurfaceGl->getContextForShareContext(); -} - -EmulatedEglContextPtr FrameBuffer::Impl::getContext_locked(HandleType p_context) { - return gfxstream::base::findOrDefault(m_contexts, p_context); -} - -EmulatedEglWindowSurfacePtr FrameBuffer::Impl::getWindowSurface_locked(HandleType p_windowsurface) { - return gfxstream::base::findOrDefault(m_windows, p_windowsurface).first; + return m_emulationGl->getGlobalEGLContext(); } TextureDraw* FrameBuffer::Impl::getTextureDraw() const { ENSURE_GL_EMULATION_VALUE(nullptr); - return m_emulationGl->mTextureDraw.get(); + return m_emulationGl->getTextureDraw(); } bool FrameBuffer::Impl::isFastBlitSupported() const { @@ -4547,140 +4207,47 @@ void FrameBuffer::Impl::disableFastBlitForTesting() { } HandleType FrameBuffer::Impl::createEmulatedEglImage(HandleType contextHandle, EGLenum target, - GLuint buffer) { + GLuint buffer) NO_THREAD_SAFETY_ANALYSIS { ENSURE_GL_EMULATION_VALUE(0); AutoLock mutex(m_lock); - - EmulatedEglContext* context = nullptr; - if (contextHandle) { - gfxstream::base::AutoWriteLock contextLock(m_contextStructureLock); - - auto it = m_contexts.find(contextHandle); - if (it == m_contexts.end()) { - GFXSTREAM_ERROR("Failed to find EmulatedEglContext:%d", contextHandle); - return 0; - } - - context = it->second.get(); - } - - auto image = m_emulationGl->createEmulatedEglImage(context, target, - reinterpret_cast(buffer)); - if (!image) { - GFXSTREAM_ERROR("Failed to create EmulatedEglImage"); - return 0; - } - - HandleType imageHandle = image->getHandle(); - - m_images[imageHandle] = std::move(image); - - RenderThreadInfo* tInfo = RenderThreadInfo::get(); - uint64_t puid = tInfo->m_puid; - if (puid) { - m_procOwnedEmulatedEglImages[puid].insert(imageHandle); - } - return imageHandle; + return m_emulationGl->createEmulatedEglImage(contextHandle, target, + reinterpret_cast(buffer)); } -bool FrameBuffer::Impl::destroyEmulatedEglImage(HandleType imageHandle) { +bool FrameBuffer::Impl::destroyEmulatedEglImage(HandleType imageHandle) NO_THREAD_SAFETY_ANALYSIS { ENSURE_GL_EMULATION_VALUE(false); AutoLock mutex(m_lock); - - auto imageIt = m_images.find(imageHandle); - if (imageIt == m_images.end()) { - GFXSTREAM_ERROR("Failed to find EmulatedEglImage:%d", imageHandle); - return false; - } - auto& image = imageIt->second; - - EGLBoolean success = image->destroy(); - m_images.erase(imageIt); - - RenderThreadInfo* tInfo = RenderThreadInfo::get(); - uint64_t puid = tInfo->m_puid; - if (puid) { - m_procOwnedEmulatedEglImages[puid].erase(imageHandle); - // We don't explicitly call m_procOwnedEmulatedEglImages.erase(puid) when the - // size reaches 0, since it could go between zero and one many times in - // the lifetime of a process. It will be cleaned up by - // cleanupProcGLObjects(puid) when the process is dead. - } - return (success == EGL_TRUE); + return m_emulationGl->destroyEmulatedEglImage(imageHandle); } -bool FrameBuffer::Impl::flushEmulatedEglWindowSurfaceColorBuffer(HandleType p_surface) { +bool FrameBuffer::Impl::flushEmulatedEglWindowSurfaceColorBuffer(HandleType p_surface) + NO_THREAD_SAFETY_ANALYSIS { + ENSURE_GL_EMULATION_VALUE(false); AutoLock mutex(m_lock); - - auto it = m_windows.find(p_surface); - if (it == m_windows.end()) { - GFXSTREAM_ERROR("FB::flushEmulatedEglWindowSurfaceColorBuffer: window handle %#x not found", - p_surface); - // bad surface handle - return false; - } - - EmulatedEglWindowSurface* surface = it->second.first.get(); - surface->flushColorBuffer(); - - return true; + return m_emulationGl->flushEmulatedEglWindowSurfaceColorBuffer(p_surface); } void FrameBuffer::Impl::fillGLESUsages(android_studio::EmulatorGLESUsages* usages) { - if (s_egl.eglFillUsages) { - s_egl.eglFillUsages(usages); + if (m_emulationGl) { + m_emulationGl->fillGlesUsages(usages); } } void* FrameBuffer::Impl::platformCreateSharedEglContext(void) { + ENSURE_GL_EMULATION_VALUE(nullptr); AutoLock lock(m_lock); - - EGLContext context = 0; - EGLSurface surface = 0; - createSharedTrivialContext(&context, &surface); - - void* underlyingContext = s_egl.eglGetNativeContextANDROID(getDisplay(), context); - if (!underlyingContext) { - GFXSTREAM_ERROR("Error: Underlying egl backend could not produce a native EGL context."); - return nullptr; - } - - m_platformEglContexts[underlyingContext] = {context, surface}; - -#if defined(__QNX__) - EGLDisplay currDisplay = eglGetCurrentDisplay(); - EGLSurface currRead = eglGetCurrentSurface(EGL_READ); - EGLSurface currDraw = eglGetCurrentSurface(EGL_DRAW); - EGLSurface currContext = eglGetCurrentContext(); - // Make this context current to ensure thread-state is initialized - s_egl.eglMakeCurrent(getDisplay(), surface, surface, context); - // Revert back to original state - s_egl.eglMakeCurrent(currDisplay, currRead, currDraw, currContext); -#endif - - return underlyingContext; + return m_emulationGl->platformCreateSharedEglContext(); } bool FrameBuffer::Impl::platformDestroySharedEglContext(void* underlyingContext) { + ENSURE_GL_EMULATION_VALUE(false); AutoLock lock(m_lock); - - auto it = m_platformEglContexts.find(underlyingContext); - if (it == m_platformEglContexts.end()) { - GFXSTREAM_ERROR( - "Error: Could not find underlying egl context %p (perhaps already destroyed?)", - underlyingContext); - return false; - } - - destroySharedTrivialContext(it->second.context, it->second.surface); - - m_platformEglContexts.erase(it); - - return true; + return m_emulationGl->platformDestroySharedEglContext(underlyingContext); } bool FrameBuffer::Impl::flushColorBufferFromGl(HandleType colorBufferHandle) { - auto colorBuffer = findColorBuffer(colorBufferHandle); + ColorBufferPtr colorBuffer = + std::static_pointer_cast(findColorBuffer(colorBufferHandle)); if (!colorBuffer) { GFXSTREAM_ERROR("%s: Failed to find ColorBuffer:%d", __func__, colorBufferHandle); return false; @@ -4694,33 +4261,35 @@ bool FrameBuffer::Impl::invalidateColorBufferForGl(HandleType colorBufferHandle) GFXSTREAM_ERROR("Failed to find ColorBuffer: %d", colorBufferHandle); return false; } - return colorBuffer->invalidateForGl(); + return colorBuffer->invalidateForBackend(Backend::GL); } ContextHelper* FrameBuffer::Impl::getPbufferSurfaceContextHelper() const { ENSURE_GL_EMULATION_VALUE(nullptr); - if (!m_emulationGl->mPbufferSurface) { + auto* pbufferSurface = m_emulationGl->getPbufferSurface(); + if (!pbufferSurface) { GFXSTREAM_FATAL("EGL emulation pbuffer surface not available."); } const auto* displaySurfaceGl = - reinterpret_cast(m_emulationGl->mPbufferSurface->getImpl()); + reinterpret_cast(pbufferSurface->getImpl()); return displaySurfaceGl->getContextHelper(); } -bool FrameBuffer::Impl::bindColorBufferToTexture(HandleType p_colorbuffer) { - AutoLock mutex(m_lock); +bool FrameBuffer::Impl::bindColorBufferToTexture(HandleType colorBufferHandle) { + ENSURE_GL_EMULATION_VALUE(false); - ColorBufferPtr colorBuffer = findColorBuffer(p_colorbuffer); - if (!colorBuffer) { - // bad colorbuffer handle - return false; - } + IColorBufferRef colorBuffer = findColorBuffer(colorBufferHandle); - return colorBuffer->glOpBindToTexture(); + AutoLock mutex(m_lock); + return m_emulationGl->bindColorBufferToTexture(colorBuffer.get()); } -bool FrameBuffer::Impl::bindColorBufferToTexture2(HandleType p_colorbuffer) { +bool FrameBuffer::Impl::bindColorBufferToTexture2(HandleType colorBufferHandle) { + ENSURE_GL_EMULATION_VALUE(false); + + IColorBufferRef colorBuffer = findColorBuffer(colorBufferHandle); + // This is only called when using multi window display // It will deadlock when posting from main thread. std::unique_ptr mutex; @@ -4728,236 +4297,69 @@ bool FrameBuffer::Impl::bindColorBufferToTexture2(HandleType p_colorbuffer) { mutex = std::make_unique(m_lock); } - ColorBufferPtr colorBuffer = findColorBuffer(p_colorbuffer); - if (!colorBuffer) { - // bad colorbuffer handle - return false; - } - - if (!colorBuffer->canUseGlOps()) { - // cannot call glOpBindToTexture2 without a valid gl colorbuffer - static bool errorReported = false; - if (!errorReported) { - GFXSTREAM_ERROR("%s: Cannot use GL colorbuffer operations", __func__); - errorReported = true; - } - return false; - } - - return colorBuffer->glOpBindToTexture2(); + return m_emulationGl->bindColorBufferToTexture2(colorBuffer.get()); } -bool FrameBuffer::Impl::bindColorBufferToRenderbuffer(HandleType p_colorbuffer) { - AutoLock mutex(m_lock); +bool FrameBuffer::Impl::bindColorBufferToRenderbuffer(HandleType colorBufferHandle) { + ENSURE_GL_EMULATION_VALUE(false); - ColorBufferPtr colorBuffer = findColorBuffer(p_colorbuffer); - if (!colorBuffer) { - // bad colorbuffer handle - return false; - } + IColorBufferRef colorBuffer = findColorBuffer(colorBufferHandle); - return colorBuffer->glOpBindToRenderbuffer(); + AutoLock mutex(m_lock); + return m_emulationGl->bindColorBufferToRenderbuffer(colorBuffer.get()); } bool FrameBuffer::Impl::bindContext(HandleType p_context, HandleType p_drawSurface, - HandleType p_readSurface) { + HandleType p_readSurface) NO_THREAD_SAFETY_ANALYSIS { + ENSURE_GL_EMULATION_VALUE(false); if (m_shuttingDown) { return false; } AutoLock mutex(m_lock); - EmulatedEglWindowSurfacePtr draw, read; - EmulatedEglContextPtr ctx; - - // - // if this is not an unbind operation - make sure all handles are good - // - if (p_context || p_drawSurface || p_readSurface) { - ctx = getContext_locked(p_context); - if (!ctx) return false; - auto drawWindowIt = m_windows.find(p_drawSurface); - if (drawWindowIt == m_windows.end()) { - // bad surface handle - return false; - } - draw = (*drawWindowIt).second.first; - - if (p_readSurface != p_drawSurface) { - auto readWindowIt = m_windows.find(p_readSurface); - if (readWindowIt == m_windows.end()) { - // bad surface handle - return false; - } - read = (*readWindowIt).second.first; - } else { - read = draw; - } - } else { - // if unbind operation, sweep color buffers + if (!p_context && !p_drawSurface && !p_readSurface) { sweepColorBuffersLocked(); } - if (!s_egl.eglMakeCurrent(getDisplay(), draw ? draw->getEGLSurface() : EGL_NO_SURFACE, - read ? read->getEGLSurface() : EGL_NO_SURFACE, - ctx ? ctx->getEGLContext() : EGL_NO_CONTEXT)) { - GFXSTREAM_ERROR("eglMakeCurrent failed"); - return false; - } - - // - // Bind the surface(s) to the context - // - RenderThreadInfoGl* const tinfo = RenderThreadInfoGl::get(); - if (!tinfo) { - GFXSTREAM_FATAL("RenderThreadGl not available."); - } - - EmulatedEglWindowSurfacePtr bindDraw, bindRead; - if (draw.get() == NULL && read.get() == NULL) { - // Unbind the current read and draw surfaces from the context - bindDraw = tinfo->currDrawSurf; - bindRead = tinfo->currReadSurf; - } else { - bindDraw = draw; - bindRead = read; - } - - if (bindDraw.get() != NULL && bindRead.get() != NULL) { - if (bindDraw.get() != bindRead.get()) { - bindDraw->bind(ctx, EmulatedEglWindowSurface::BIND_DRAW); - bindRead->bind(ctx, EmulatedEglWindowSurface::BIND_READ); - } else { - bindDraw->bind(ctx, EmulatedEglWindowSurface::BIND_READDRAW); - } - } - - // - // update thread info with current bound context - // - tinfo->currContext = ctx; - tinfo->currDrawSurf = draw; - tinfo->currReadSurf = read; - if (ctx) { - if (ctx->clientVersion() > GLESApi_CM) - tinfo->m_gl2Dec.setContextData(&ctx->decoderContextData()); - else - tinfo->m_glDec.setContextData(&ctx->decoderContextData()); - } else { - tinfo->m_glDec.setContextData(NULL); - tinfo->m_gl2Dec.setContextData(NULL); - } - return true; + return m_emulationGl->bindContext(p_context, p_drawSurface, p_readSurface); } void FrameBuffer::Impl::createYUVTextures(uint32_t type, uint32_t count, int width, int height, - uint32_t* output) { - auto formatOpt = GetGfxstreamFormat(m_features, static_cast(type)); - if (!formatOpt) { - GFXSTREAM_ERROR("Unsupported framework format %d", type); - return; - } - auto format = *formatOpt; - + uint32_t* output) NO_THREAD_SAFETY_ANALYSIS { + ENSURE_GL_EMULATION_VOID(); AutoLock mutex(m_lock); - auto contextHelper = getPbufferSurfaceContextHelper(); - if (!contextHelper) { - // This should not be called in vulkan-only mode - GFXSTREAM_ERROR("%s: invalid pbuffer surface context", __func__); - return; - } - RecursiveScopedContextBind bind(contextHelper); - if (!bind.isOk()) { - GFXSTREAM_ERROR("%s: could not bind context helper", __func__); - return; - } - for (uint32_t i = 0; i < count; ++i) { - if (format == GfxstreamFormat::NV12 || format == GfxstreamFormat::NV21) { - YUVConverter::createYUVGLTex(GL_TEXTURE0, width, height, format, YuvPlane::Y, &output[2 * i]); - YUVConverter::createYUVGLTex(GL_TEXTURE1, width / 2, height / 2, format, YuvPlane::UV, &output[2 * i + 1]); - } else if (format == GfxstreamFormat::YV12 || format == GfxstreamFormat::YV21) { - YUVConverter::createYUVGLTex(GL_TEXTURE0, width, height, format, YuvPlane::Y, &output[3 * i]); - YUVConverter::createYUVGLTex(GL_TEXTURE1, width / 2, height / 2, format, YuvPlane::U, &output[3 * i + 1]); - YUVConverter::createYUVGLTex(GL_TEXTURE2, width / 2, height / 2, format, YuvPlane::V, &output[3 * i + 2]); - } - } + m_emulationGl->createYUVTextures(type, count, width, height, output); } -void FrameBuffer::Impl::destroyYUVTextures(uint32_t type, uint32_t count, uint32_t* textures) { - auto formatOpt = GetGfxstreamFormat(m_features, static_cast(type)); - if (!formatOpt) { - GFXSTREAM_ERROR("Unsupported framework format %d", type); - return; - } - auto format = *formatOpt; - +void FrameBuffer::Impl::destroyYUVTextures(uint32_t type, uint32_t count, + uint32_t* textures) NO_THREAD_SAFETY_ANALYSIS { + ENSURE_GL_EMULATION_VOID(); AutoLock mutex(m_lock); - RecursiveScopedContextBind bind(getPbufferSurfaceContextHelper()); - if (format == GfxstreamFormat::NV12 || format == GfxstreamFormat::NV21) { - s_gles2.glDeleteTextures(2 * count, textures); - } else if (format == GfxstreamFormat::YV12 || format == GfxstreamFormat::YV21) { - s_gles2.glDeleteTextures(3 * count, textures); - } + m_emulationGl->destroyYUVTextures(type, count, textures); } -void FrameBuffer::Impl::updateYUVTextures(uint32_t type, uint32_t* textures, void* privData, void* func) { - auto formatOpt = GetGfxstreamFormat(m_features, static_cast(type)); - if (!formatOpt) { - GFXSTREAM_ERROR("Unsupported framework format %d", type); - return; - } - auto format = *formatOpt; - +void FrameBuffer::Impl::updateYUVTextures(uint32_t type, uint32_t* textures, void* privData, + void* func) NO_THREAD_SAFETY_ANALYSIS { + ENSURE_GL_EMULATION_VOID(); AutoLock mutex(m_lock); - RecursiveScopedContextBind bind(getPbufferSurfaceContextHelper()); - - yuv_updater_t updater = (yuv_updater_t)func; - uint32_t gtextures[3] = {0, 0, 0}; - - if (format == GfxstreamFormat::NV12 || format == GfxstreamFormat::NV21) { - gtextures[0] = s_gles2.glGetGlobalTexName(textures[0]); - gtextures[1] = s_gles2.glGetGlobalTexName(textures[1]); - } else if (format == GfxstreamFormat::YV12 || format == GfxstreamFormat::YV21) { - gtextures[0] = s_gles2.glGetGlobalTexName(textures[0]); - gtextures[1] = s_gles2.glGetGlobalTexName(textures[1]); - gtextures[2] = s_gles2.glGetGlobalTexName(textures[2]); - } - -#ifdef __APPLE__ - EGLContext prevContext = s_egl.eglGetCurrentContext(); - auto mydisp = EglGlobalInfo::getInstance()->getDisplayFromDisplayType(EGL_DEFAULT_DISPLAY); - void* nativecontext = mydisp->getLowLevelContext(prevContext); - struct MediaNativeCallerData callerdata; - callerdata.ctx = nativecontext; - callerdata.converter = nsConvertVideoFrameToNV12Textures; - void* pcallerdata = &callerdata; -#else - void* pcallerdata = nullptr; -#endif - - updater(privData, type, gtextures, pcallerdata); + m_emulationGl->updateYUVTextures(type, textures, privData, func); } void FrameBuffer::Impl::swapTexturesAndUpdateColorBuffer(uint32_t p_colorbuffer, int x, int y, int width, int height, uint32_t format, uint32_t type, uint32_t texturesType, uint32_t* textures) { - auto texturesFormatOpt = GetGfxstreamFormat(m_features, (FrameworkFormat)texturesType); - if (!texturesFormatOpt) { - GFXSTREAM_ERROR("Unsupported framework format %d", texturesType); + AutoLock mutex(m_lock); + IColorBufferRef colorBuffer = findColorBuffer(p_colorbuffer); + if (!colorBuffer) { + // bad colorbuffer handle return; } - auto texturesFormat = *texturesFormatOpt; - - { - AutoLock mutex(m_lock); - ColorBufferPtr colorBuffer = findColorBuffer(p_colorbuffer); - if (!colorBuffer) { - // bad colorbuffer handle - return; - } - colorBuffer->glOpSwapYuvTexturesAndUpdate(format, type, texturesFormat, textures); - } +#if GFXSTREAM_ENABLE_HOST_GLES + m_emulationGl->swapTexturesAndUpdateColorBuffer(colorBuffer.get(), format, type, texturesType, + textures); +#endif } void FrameBuffer::Impl::asyncWaitForGpuWithCb(uint64_t eglsync, FenceCompletionCallback cb) { @@ -5080,6 +4482,8 @@ void FrameBuffer::finalize() { /*static*/ FrameBuffer* FrameBuffer::getFB() { return sFrameBuffer; } +GlobalState* FrameBuffer::getGlobalState() { return mImpl.get(); } + bool FrameBuffer::setupSubWindow(FBNativeWindowType p_window, int wx, int wy, int ww, int wh, int fbw, int fbh, float dpr, float zRot, bool deleteExisting, bool hideWindow) { @@ -5262,8 +4666,8 @@ AsyncResult FrameBuffer::composeWithCallback(uint32_t bufferSize, void* buffer, return mImpl->composeWithCallback(bufferSize, buffer, callback); } -void FrameBuffer::onSave(gfxstream::Stream* stream, const ITextureSaverPtr& textureSaver) { - mImpl->onSave(stream, textureSaver); +bool FrameBuffer::onSave(gfxstream::Stream* stream, const ITextureSaverPtr& textureSaver) { + return mImpl->onSave(stream, textureSaver); } bool FrameBuffer::onLoad(gfxstream::Stream* stream, const ITextureLoaderPtr& textureLoader) { @@ -5318,7 +4722,7 @@ int FrameBuffer::getScreenshot(unsigned int nChannels, unsigned int* width, unsi } int FrameBuffer::getColorBufferScreenshot( - ColorBuffer* cb, int targetWidth, int targetHeight, int skinRotation, + IColorBuffer* cb, int targetWidth, int targetHeight, int skinRotation, GfxstreamFormat pixelsFormat, void* outPixels, const Rect& rect, const std::optional>& colorTransform) { return mImpl->getColorBufferScreenshot(cb, targetWidth, targetHeight, skinRotation, @@ -5327,7 +4731,7 @@ int FrameBuffer::getColorBufferScreenshot( void FrameBuffer::onLastColorBufferRef(uint32_t handle) { mImpl->onLastColorBufferRef(handle); } -ColorBufferPtr FrameBuffer::findColorBuffer(HandleType p_colorbuffer) { +IColorBufferRef FrameBuffer::findColorBuffer(HandleType p_colorbuffer) { return mImpl->findColorBuffer(p_colorbuffer); } @@ -5397,16 +4801,6 @@ void FrameBuffer::setGuestManagedColorBufferLifetime(bool guestManaged) { mImpl->setGuestManagedColorBufferLifetime(guestManaged); } -std::unique_ptr FrameBuffer::borrowColorBufferForComposition( - uint32_t colorBufferHandle, bool colorBufferIsTarget) { - return mImpl->borrowColorBufferForComposition(colorBufferHandle, colorBufferIsTarget); -} - -std::unique_ptr FrameBuffer::borrowColorBufferForDisplay( - uint32_t colorBufferHandle) { - return mImpl->borrowColorBufferForDisplay(colorBufferHandle); -} - void FrameBuffer::setVsyncHz(int vsyncHz) { mImpl->setVsyncHz(vsyncHz); } void FrameBuffer::scheduleVsyncTask(VsyncThread::VsyncTask task) { mImpl->scheduleVsyncTask(task); } @@ -5460,6 +4854,10 @@ int32_t FrameBuffer::mapGpaToBufferHandle(uint32_t bufferHandle, uint64_t gpa, u #if GFXSTREAM_ENABLE_HOST_GLES +gl::EmulationGl* FrameBuffer::getEmulationGl() { + return mImpl ? mImpl->getEmulationGlPtr() : nullptr; +} + HandleType FrameBuffer::getEmulatedEglWindowSurfaceColorBufferHandle(HandleType p_surface) { return mImpl->getEmulatedEglWindowSurfaceColorBufferHandle(p_surface); } @@ -5540,17 +4938,7 @@ void FrameBuffer::drainGlRenderThreadContexts() { mImpl->drainGlRenderThreadCont void FrameBuffer::drainGlRenderThreadSurfaces() { mImpl->drainGlRenderThreadSurfaces(); } -void FrameBuffer::postLoadRenderThreadContextSurfacePtrs() { - mImpl->postLoadRenderThreadContextSurfacePtrs(); -} - -EGLDisplay FrameBuffer::getDisplay() const { return mImpl->getDisplay(); } - -EGLSurface FrameBuffer::getWindowSurface() const { return mImpl->getWindowSurface(); } - -EGLContext FrameBuffer::getContext() const { return mImpl->getContext(); } - -EGLConfig FrameBuffer::getConfig() const { return mImpl->getConfig(); } +bool FrameBuffer::getRenderOpt(RenderOpt* opt) const { return mImpl->getRenderOpt(opt); } EGLContext FrameBuffer::getGlobalEGLContext() const { return mImpl->getGlobalEGLContext(); } diff --git a/host/frame_buffer.h b/host/frame_buffer.h index 865f31424..2c1586b2b 100644 --- a/host/frame_buffer.h +++ b/host/frame_buffer.h @@ -30,23 +30,22 @@ #include #include "buffer.h" -#include "color_buffer.h" -#include "framework_formats.h" -#include "handle.h" -#include "post_commands.h" -#include "vsync_thread.h" #include "gfxstream/AsyncResult.h" #include "gfxstream/EventNotificationSupport.h" -#include "gfxstream/host/process_resources.h" -#include "gfxstream/host/borrowed_image.h" +#include "gfxstream/host/color_buffer_interface.h" #include "gfxstream/host/external_object_manager.h" -#include "gfxstream/host/gl_enums.h" +#include "gfxstream/host/framework_formats.h" #include "gfxstream/host/gfxstream_format.h" +#include "gfxstream/host/gl_enums.h" +#include "gfxstream/host/handle.h" +#include "gfxstream/host/post_commands.h" +#include "gfxstream/host/process_resources.h" #include "gfxstream/host/vk_enums.h" #include "render-utils/Renderer.h" #include "render-utils/render_api.h" #include "render-utils/stream.h" #include "render-utils/virtio_gpu_ops.h" +#include "vsync_thread.h" // values for 'param' argument of rcGetFBParam #define FB_WIDTH 1 @@ -58,8 +57,11 @@ #define FB_MAX_SWAP_INTERVAL 7 namespace gfxstream { +struct RenderOpt; namespace host { +class GlobalState; + // The FrameBuffer class holds the global state of the emulation library on // top of the underlying EGL/GLES implementation. It should probably be // named "Display" instead of "FrameBuffer". @@ -113,6 +115,8 @@ class FrameBuffer : public gfxstream::base::EventNotificationSupport>& colorTransform); void onLastColorBufferRef(uint32_t handle); - ColorBufferPtr findColorBuffer(HandleType p_colorbuffer); + IColorBufferRef findColorBuffer(HandleType p_colorbuffer); BufferPtr findBuffer(HandleType p_buffer); void registerProcessCleanupCallback(void* key, uint64_t contextId, @@ -412,10 +416,6 @@ class FrameBuffer : public gfxstream::base::EventNotificationSupport borrowColorBufferForComposition(uint32_t colorBufferHandle, - bool colorBufferIsTarget); - std::unique_ptr borrowColorBufferForDisplay(uint32_t colorBufferHandle); - void logVulkanDeviceLost(); void setVsyncHz(int vsyncHz); @@ -441,6 +441,7 @@ class FrameBuffer : public gfxstream::base::EventNotificationSupport +#include + #include "frame_buffer.h" #include +#include -#include -#include - -#include "render_thread_info.h" #include "gfxstream/common/testing/graphics_test_environment.h" #include "gfxstream/files/PathUtils.h" +#include "gfxstream/host/color_buffer_interface.h" #include "gfxstream/host/display_operations.h" #include "gfxstream/host/features.h" #include "gfxstream/host/file_stream.h" #include "gfxstream/host/gfxstream_format.h" #include "gfxstream/host/mem_stream.h" -#include "gfxstream/host/window_operations.h" -#include "gfxstream/system/System.h" #include "gfxstream/host/testing/GLSnapshotTesting.h" #include "gfxstream/host/testing/GLTestUtils.h" #include "gfxstream/host/testing/OSWindow.h" #include "gfxstream/host/testing/SampleApplication.h" #include "gfxstream/host/testing/ShaderUtils.h" +#include "gfxstream/host/window_operations.h" +#include "gfxstream/system/System.h" +#include "render_channel_impl.h" +#include "render_thread_info.h" #ifdef _MSC_VER #include "gfxstream/msvc.h" @@ -99,7 +102,7 @@ class FrameBufferTest : public ::testing::Test { EXPECT_EQ(EGL_SUCCESS, egl->eglGetError()); mRenderThreadInfo = new RenderThreadInfo(); - mRenderThreadInfo->initGl(); + mRenderThreadInfo->initGl(mFb->getEmulationGl()); } virtual void TearDown() override { @@ -512,7 +515,8 @@ TEST_F(FrameBufferTest, SnapshotSingleColorBuffer) { // bug: 111360779 // Tests that the ColorBuffer is successfully updated even if a reformat happens // on restore; the reformat may mess up the texture restore logic. -// In ColorBuffer::subUpdate, this test is known to fail if touch() is moved after the reformat. +// In ColorBuffer::subUpdate, this test is known to fail if touch() is moved after the +// reformat. TEST_F(FrameBufferTest, SnapshotColorBufferSubUpdateRestore) { HandleType handle = mFb->createColorBuffer(mWidth, mHeight, GfxstreamFormat::R8G8B8A8_UNORM); @@ -533,27 +537,6 @@ TEST_F(FrameBufferTest, SnapshotColorBufferSubUpdateRestore) { mFb->closeColorBuffer(handle); } -// bug: 111558407 -// Tests that ColorBuffer's blit path is retained on save/restore. -TEST_F(FrameBufferTest, SnapshotFastBlitRestore) { - HandleType handle = mFb->createColorBuffer(mWidth, mHeight, GfxstreamFormat::R8G8B8A8_UNORM); - - EXPECT_TRUE(mFb->isFastBlitSupported()); - - mFb->lock(); - EXPECT_EQ(mFb->isFastBlitSupported(), mFb->findColorBuffer(handle)->glOpIsFastBlitSupported()); - mFb->unlock(); - - saveSnapshot(); - loadSnapshot(); - - mFb->lock(); - EXPECT_EQ(mFb->isFastBlitSupported(), mFb->findColorBuffer(handle)->glOpIsFastBlitSupported()); - mFb->unlock(); - - mFb->closeColorBuffer(handle); -} - // Tests rate of draw calls with no guest/host communication, but with translator. static constexpr uint32_t kDrawCallLimit = 50000; @@ -737,7 +720,8 @@ TEST_F(FrameBufferTest, CreateColorBufferBGRA) { } // Test ColorBuffer with GL_RGBA, but read back as GL_BGRA, so that R/B are switched. -// TODO: This doesn't work on NVIDIA EGL, it issues GL_INVALID_OPERATION if the format doesn't match. +// TODO: This doesn't work on NVIDIA EGL, it issues GL_INVALID_OPERATION if the format doesn't +// match. TEST_F(FrameBufferTest, DISABLED_ReadColorBufferSwitchRedBlue) { HandleType handle = mFb->createColorBuffer(mWidth, mHeight, GfxstreamFormat::R8G8B8A8_UNORM); @@ -891,6 +875,83 @@ TEST_F(FrameBufferTest, ComposeMultiDisplay) { mFb->destroyEmulatedEglWindowSurface(surface); } +class RenderThreadDeadlockTest : public ::testing::Test { + protected: + static void SetUpTestSuite() { + ASSERT_THAT(gfxstream::testing::SetupGraphicsTestEnvironment(), ::testing::IsTrue()) + << "Failed to configure graphics test environment!"; + } + + void SetUp() override { + const EGLDispatch* egl = LazyLoadedEGLDispatch::get(); + ASSERT_NE(nullptr, egl); + ASSERT_NE(nullptr, LazyLoadedGLESv2Dispatch::get()); + + bool useHostGpu = shouldUseHostGpu(); + + FeatureSet features = {}; + features.EglOnEgl.setEnabled(!useHostGpu); + features.Vulkan.setEnabled(true); + features.VulkanQueueSubmitWithCommands.setEnabled(true); + + gfxstream::base::setEnvironmentVariable("ANDROID_EMU_HEADLESS", "1"); + EXPECT_TRUE(FrameBuffer::initialize(256, 256, features, false)); + } + + void TearDown() override { + FrameBuffer::finalize(); + } +}; + +TEST_F(RenderThreadDeadlockTest, ReproDeadlockOnTeardown) { + auto fb = FrameBuffer::getFB(); + ASSERT_NE(nullptr, fb); + if (!fb->hasEmulationVk()) { + GTEST_SKIP() << "Vulkan emulation not supported on this host."; + } + + const uint32_t contextId = 12345; + fb->createGraphicsProcessResources(contextId); + + auto channel = std::make_unique(nullptr, contextId); + ASSERT_NE(nullptr, channel->renderThread()); + + RenderChannel::Buffer buffer; + uint32_t flags = 0; + uint32_t opcode = 200000000; // OP_vkCreateInstance + uint32_t packetLen = 12; + uint32_t seqno = 2; + + buffer.resize(16); + std::memcpy(buffer.data(), &flags, sizeof(flags)); + std::memcpy(buffer.data() + 4, &opcode, sizeof(opcode)); + std::memcpy(buffer.data() + 8, &packetLen, sizeof(packetLen)); + std::memcpy(buffer.data() + 12, &seqno, sizeof(seqno)); + + channel->tryWrite(std::move(buffer)); + + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + + std::promise teardownPromise; + std::future teardownFuture = teardownPromise.get_future(); + + std::thread teardownThread([&]() { + channel->stop(); + channel.reset(); + teardownPromise.set_value(); + }); + + std::future_status status = teardownFuture.wait_for(std::chrono::seconds(3)); + if (status == std::future_status::timeout) { + teardownThread.detach(); + ADD_FAILURE() << "Deadlock detected! Channel teardown timed out after 3 seconds."; + } else { + teardownThread.join(); + } + + fb->removeGraphicsProcessResources(contextId); +} + } // namespace } // namespace host } // namespace gfxstream diff --git a/host/gfx_stream_backend_init_override.cpp b/host/gfx_stream_backend_init_override.cpp deleted file mode 100644 index 9d8859d64..000000000 --- a/host/gfx_stream_backend_init_override.cpp +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (C) 2022 The Android Open Source Project -// -// 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 "render-utils/virtio-gpu-gfxstream-renderer.h" - -void gfxstream_backend_init_product_override() {} diff --git a/host/gl/Android.bp b/host/gl/Android.bp index 1cd9d65f1..8af34fc87 100644 --- a/host/gl/Android.bp +++ b/host/gl/Android.bp @@ -34,6 +34,7 @@ cc_library_static { "emulation_gl.cpp", "gles_version_detector.cpp", "pixel_read_formats.cpp", + "post_worker_gl.cpp", "readback_worker_gl.cpp", "render_thread_info_gl.cpp", "texture_draw.cpp", @@ -41,12 +42,13 @@ cc_library_static { "yuv_converter.cpp", ], header_libs: [ - "libgfxstream_thirdparty_opengl_headers", "libgfxstream_backend_headers", "libgfxstream_thirdparty_glm", + "libgfxstream_thirdparty_opengl_headers", ], static_libs: [ "libgfxstream_common_base", + "libgfxstream_common_logging", "libgfxstream_host_common", "libgfxstream_host_decoder_common", "libgfxstream_host_features", @@ -54,7 +56,6 @@ cc_library_static { "libgfxstream_host_gles2_dec", "libgfxstream_host_glestranslator_glcommon", "libgfxstream_host_glsnapshot", - "libgfxstream_common_logging", "libgfxstream_host_openglesdispatch", "libgfxstream_host_renderdoc", ], diff --git a/host/gl/BUILD.bazel b/host/gl/BUILD.bazel index eefff508d..a9dfe430f 100644 --- a/host/gl/BUILD.bazel +++ b/host/gl/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -23,6 +23,7 @@ cc_library( "emulation_gl.cpp", "gles_version_detector.cpp", "pixel_read_formats.cpp", + "post_worker_gl.cpp", "readback_worker_gl.cpp", "render_thread_info_gl.cpp", "texture_draw.cpp", @@ -30,7 +31,6 @@ cc_library( "yuv_converter.cpp", ], hdrs = [ - "borrowed_image_gl.h", "buffer_gl.h", "color_buffer_gl.h", "compositor_gl.h", @@ -46,8 +46,10 @@ cc_library( "emulation_gl.h", "gles_version_detector.h", "pixel_read_formats.h", + "post_worker_gl.h", "readback_worker_gl.h", "render_thread_info_gl.h", + "stale_ptr_registry.h", "texture_draw.h", "texture_resize.h", "yuv_converter.h", @@ -60,12 +62,12 @@ cc_library( includes = [ ".", ], + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ "//common/base:gfxstream_common_base", "//common/logging:gfxstream_common_logging", "//common/utils:gfxstream_common_utils", "//host:gfxstream_backend_headers", - "//host:gfxstream_host_headers", "//host/common:gfxstream_host_common", "//host/decoder_common:gfxstream_host_decoder_common", "//host/features:gfxstream_host_features", diff --git a/host/gl/CMakeLists.txt b/host/gl/CMakeLists.txt index 347529ee7..fbb7a3daf 100644 --- a/host/gl/CMakeLists.txt +++ b/host/gl/CMakeLists.txt @@ -38,6 +38,7 @@ add_library(gfxstream-gl-server emulation_gl.cpp gles_version_detector.cpp pixel_read_formats.cpp + post_worker_gl.cpp readback_worker_gl.cpp render_thread_info_gl.cpp texture_draw.cpp diff --git a/host/gl/OpenGLESDispatch/BUILD.bazel b/host/gl/OpenGLESDispatch/BUILD.bazel index 16f40cd0f..23cbf9f78 100644 --- a/host/gl/OpenGLESDispatch/BUILD.bazel +++ b/host/gl/OpenGLESDispatch/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -19,6 +19,7 @@ cc_library( copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, includes = ["include"], + linkopts = GFXSTREAM_HOST_LINKOPTS, textual_hdrs = [ "include/OpenGLESDispatch/gldefs.h", "include/OpenGLESDispatch/gles_common_for_gles1_static_translator_namespaced_header.h", @@ -78,6 +79,7 @@ cc_library( "-Wno-extern-c-compat", ], defines = GFXSTREAM_HOST_DEFINES, + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ ":gfxstream_host_openglesdispatch_headers", "//host/common:gfxstream_host_common", diff --git a/host/gl/borrowed_image_gl.h b/host/gl/borrowed_image_gl.h deleted file mode 100644 index 12dd8423c..000000000 --- a/host/gl/borrowed_image_gl.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2022 The Android Open Source Project -// -// 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 expresso or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include -#include -#include -#include - -#include - -#include "gfxstream/host/borrowed_image.h" - -namespace gfxstream { -namespace host { -namespace gl { - -struct BorrowedImageInfoGl : public BorrowedImageInfo { - GLuint texture = 0; - - // Functor called once commands using this Image have been - // issued (useful for setting a GL sync). - std::function onCommandsIssued; -}; - -} // namespace gl -} // namespace host -} // namespace gfxstream diff --git a/host/gl/buffer_gl.h b/host/gl/buffer_gl.h index a4c4ab9fc..4ae64c7d6 100644 --- a/host/gl/buffer_gl.h +++ b/host/gl/buffer_gl.h @@ -22,7 +22,7 @@ #include #include "context_helper.h" -#include "handle.h" +#include "gfxstream/host/handle.h" #include "render-utils/stream.h" namespace gfxstream { diff --git a/host/gl/color_buffer_gl.cpp b/host/gl/color_buffer_gl.cpp index 5577fbdf2..a7fa337aa 100644 --- a/host/gl/color_buffer_gl.cpp +++ b/host/gl/color_buffer_gl.cpp @@ -24,14 +24,13 @@ #include "OpenGLESDispatch/DispatchTables.h" #include "OpenGLESDispatch/EGLDispatch.h" -#include "borrowed_image_gl.h" #include "common/gl_utils.h" #include "debug_gl.h" #include "gfxstream/host/renderer_operations.h" -#include "gl/yuv_converter.h" #include "render_thread_info_gl.h" #include "texture_draw.h" #include "texture_resize.h" +#include "yuv_converter.h" namespace gfxstream { namespace host { @@ -638,7 +637,7 @@ bool ColorBufferGl::readPixelsScaled(int width, int height, int rotation, const std::vector tmpPixels; void* readPixelsDst = pixels; if (needConvert4To3Channel) { - tmpPixels.resize(width * height * 4); + tmpPixels.resize((uint64_t)width * (uint64_t)height * 4); pixelDataComponents = GL_RGBA; readPixelsDst = tmpPixels.data(); } @@ -1354,16 +1353,6 @@ bool ColorBufferGl::importEglNativePixmap(void* pixmap, bool preserveContent) { return true; } -std::unique_ptr ColorBufferGl::getBorrowedImageInfo() { - auto info = std::make_unique(); - info->id = mHndl; - info->width = m_width; - info->height = m_height; - info->texture = m_tex; - info->onCommandsIssued = [this]() { setSync(); }; - return info; -} - } // namespace gl } // namespace host } // namespace gfxstream diff --git a/host/gl/color_buffer_gl.h b/host/gl/color_buffer_gl.h index 7c8012e4a..937434b63 100644 --- a/host/gl/color_buffer_gl.h +++ b/host/gl/color_buffer_gl.h @@ -29,11 +29,10 @@ #include "context_helper.h" #include "gfxstream/ManagedDescriptor.h" -#include "gfxstream/host/borrowed_image.h" #include "gfxstream/host/features.h" #include "gfxstream/host/gfxstream_format.h" -#include "handle.h" -#include "hwc2.h" +#include "gfxstream/host/hwc2.h" +#include "gfxstream/host/handle.h" #include "pixel_read_formats.h" #include "render-utils/Renderer.h" #include "render-utils/stream.h" @@ -197,13 +196,12 @@ class ColorBufferGl { PixelReadFormats& pixelReadFormats); HandleType getHndl() const; + GLuint getTexture() const { return m_tex; } bool isFastBlitSupported() const { return m_fastBlitSupported; } void postLayer(const ComposeLayer& l, int frameWidth, int frameHeight, const std::optional>& colorTransform); - std::unique_ptr getBorrowedImageInfo(); - // ColorBufferGl backing change methods // // Change to opaque fd or opaque win32 handle-backed VkDeviceMemory diff --git a/host/gl/compositor_gl.cpp b/host/gl/compositor_gl.cpp index 4b0ee9c2e..ccf88159c 100644 --- a/host/gl/compositor_gl.cpp +++ b/host/gl/compositor_gl.cpp @@ -14,28 +14,18 @@ #include "compositor_gl.h" -#include "borrowed_image_gl.h" +#include "OpenGLESDispatch/DispatchTables.h" +#include "color_buffer_gl.h" #include "debug_gl.h" #include "display_surface_gl.h" -#include "OpenGLESDispatch/DispatchTables.h" -#include "texture_draw.h" #include "gfxstream/common/logging.h" +#include "texture_draw.h" namespace gfxstream { namespace host { namespace gl { namespace { -const BorrowedImageInfoGl* getInfoOrAbort(const std::unique_ptr& info) { - auto imageGl = static_cast(info.get()); - if (imageGl != nullptr) { - return imageGl; - } - - GFXSTREAM_FATAL("CompositorGl did not find BorrowedImageInfoGl"); - return nullptr; -} - std::shared_future getCompletedFuture() { std::shared_future completedFuture = std::async(std::launch::deferred, [] {}).share(); completedFuture.wait(); @@ -54,10 +44,21 @@ CompositorGl::~CompositorGl() {} Compositor::CompositionFinishedWaitable CompositorGl::compose( const CompositionRequest& composeRequest) { - const auto* targetImage = getInfoOrAbort(composeRequest.target); - const uint32_t targetWidth = targetImage->width; - const uint32_t targetHeight = targetImage->height; - const GLuint targetTexture = targetImage->texture; + auto targetCb = composeRequest.target; + if (!targetCb) { + GFXSTREAM_ERROR("CompositorGl::compose: target is null"); + return getCompletedFuture(); + } + targetCb->invalidateForBackend(Backend::GL); + auto targetCbGl = targetCb->getColorBufferGl(); + if (!targetCbGl) { + GFXSTREAM_ERROR("CompositorGl::compose: target is not GL ColorBuffer"); + return getCompletedFuture(); + } + + const uint32_t targetWidth = targetCbGl->getWidth(); + const uint32_t targetHeight = targetCbGl->getHeight(); + const GLuint targetTexture = targetCbGl->getTexture(); GL_SCOPED_DEBUG_GROUP("CompositorGl::compose() into texture:%d", targetTexture); GLint restoredViewport[4] = {0, 0, 0, 0}; @@ -76,11 +77,20 @@ Compositor::CompositionFinishedWaitable CompositorGl::compose( for (const CompositionRequestLayer& layer : composeRequest.layers) { if (layer.props.composeMode == HWC2_COMPOSITION_DEVICE) { - const BorrowedImageInfoGl* layerImage = getInfoOrAbort(layer.source); - const GLuint layerTexture = layerImage->texture; + auto layerCb = layer.source; + if (!layerCb) { + continue; + } + layerCb->invalidateForBackend(Backend::GL); + auto layerCbGl = layerCb->getColorBufferGl(); + if (!layerCbGl) { + continue; + } + + const GLuint layerTexture = layerCbGl->getTexture(); GL_SCOPED_DEBUG_GROUP("CompositorGl::compose() from layer texture:%d", layerTexture); - m_textureDraw->drawLayer(layer.props, targetWidth, targetHeight, layerImage->width, - layerImage->height, layerTexture); + m_textureDraw->drawLayer(layer.props, targetWidth, targetHeight, layerCbGl->getWidth(), + layerCbGl->getHeight(), layerTexture); } else { m_textureDraw->drawLayer(layer.props, targetWidth, targetHeight, 1, 1, 0); } @@ -92,7 +102,7 @@ Compositor::CompositionFinishedWaitable CompositorGl::compose( m_textureDraw->cleanupForDrawLayer(); - targetImage->onCommandsIssued(); + targetCbGl->setSync(); // Note: This should be returning a future when all work, both CPU and GPU, is // complete but is currently only returning a future when all CPU work is completed. diff --git a/host/gl/compositor_gl.h b/host/gl/compositor_gl.h index 8561c23a7..6a3a1b2be 100644 --- a/host/gl/compositor_gl.h +++ b/host/gl/compositor_gl.h @@ -14,14 +14,14 @@ #pragma once -#include - #include #include #include #include -#include "compositor.h" +#include + +#include "gfxstream/host/compositor.h" #include "gfxstream/host/display_surface_user.h" #include "texture_draw.h" diff --git a/host/gl/display_gl.cpp b/host/gl/display_gl.cpp index 39d4746d6..fe046282e 100644 --- a/host/gl/display_gl.cpp +++ b/host/gl/display_gl.cpp @@ -14,12 +14,13 @@ #include "display_gl.h" -#include "display_surface_gl.h" #include "OpenGLESDispatch/DispatchTables.h" #include "OpenGLESDispatch/EGLDispatch.h" -#include "texture_draw.h" +#include "color_buffer_gl.h" +#include "display_surface_gl.h" #include "gfxstream/common/logging.h" #include "gfxstream/host/display_operations.h" +#include "texture_draw.h" namespace gfxstream { namespace host { @@ -48,23 +49,25 @@ std::shared_future DisplayGl::post(const Post& post) { bool hasDrawLayer = false; for (const PostLayer& layer : post.layers) { + if (!layer.colorBuffer) continue; + auto cbGl = layer.colorBuffer->getColorBufferGl(); + if (!cbGl) continue; + if (layer.layerOptions) { if (!hasDrawLayer) { mTextureDraw->prepareForDrawLayer(); hasDrawLayer = true; } - layer.colorBuffer->glOpPostLayer(*layer.layerOptions, post.frameWidth, - post.frameHeight, post.colorTransform); + cbGl->postLayer(*layer.layerOptions, post.frameWidth, post.frameHeight, + post.colorTransform); } else if (layer.overlayOptions) { if (hasDrawLayer) { GFXSTREAM_ERROR("Cannot mix colorBuffer.postLayer with postWithOverlay!"); } - layer.colorBuffer->glOpPostViewportScaledWithOverlay( - layer.overlayOptions->rotation, - layer.overlayOptions->dx, layer.overlayOptions->dy, - layer.overlayOptions->scaleX, layer.overlayOptions->scaleY, - layer.colorTransform); + cbGl->postViewportScaledWithOverlay( + layer.overlayOptions->rotation, layer.overlayOptions->dx, layer.overlayOptions->dy, + layer.overlayOptions->scaleX, layer.overlayOptions->scaleY, layer.colorTransform); } } if (hasDrawLayer) { diff --git a/host/gl/display_gl.h b/host/gl/display_gl.h index e363fea8c..c0afd1f9a 100644 --- a/host/gl/display_gl.h +++ b/host/gl/display_gl.h @@ -22,10 +22,10 @@ #include #include -#include "color_buffer.h" -#include "hwc2.h" -#include "texture_draw.h" +#include "gfxstream/host/color_buffer_interface.h" #include "gfxstream/host/display.h" +#include "gfxstream/host/hwc2.h" +#include "texture_draw.h" namespace gfxstream { namespace host { @@ -37,20 +37,20 @@ class DisplayGl : public Display { ~DisplayGl() {} struct PostLayer { - ColorBuffer* colorBuffer = nullptr; - - std::optional layerOptions; - - // TODO: This should probably be removed and TextureDraw should - // only use drawLayer() but this is currently needed to support - // existing draw paths without depending on FrameBuffer directly. - struct OverlayOptions { - float rotation = 0.0f; - float dx = 0.0f; - float dy = 0.0f; - float scaleX = 1.0f; - float scaleY = 1.0f; - }; + IColorBuffer* colorBuffer = nullptr; + + std::optional layerOptions; + + // TODO: This should probably be removed and TextureDraw should + // only use drawLayer() but this is currently needed to support + // existing draw paths without depending on FrameBuffer directly. + struct OverlayOptions { + float rotation = 0.0f; + float dx = 0.0f; + float dy = 0.0f; + float scaleX = 1.0f; + float scaleY = 1.0f; + }; std::optional overlayOptions; const std::optional> colorTransform; diff --git a/host/gl/emulated_egl_context.h b/host/gl/emulated_egl_context.h index 238aad011..b1e74db68 100644 --- a/host/gl/emulated_egl_context.h +++ b/host/gl/emulated_egl_context.h @@ -22,7 +22,7 @@ #include #include -#include "handle.h" +#include "gfxstream/host/handle.h" #include "gfxstream/host/GLDecoderContextData.h" #include "gfxstream/host/gl_enums.h" #include "render-utils/stream.h" diff --git a/host/gl/emulated_egl_image.h b/host/gl/emulated_egl_image.h index 7fbb15e78..9119019b1 100644 --- a/host/gl/emulated_egl_image.h +++ b/host/gl/emulated_egl_image.h @@ -23,7 +23,7 @@ #include #include -#include "handle.h" +#include "gfxstream/host/handle.h" namespace gfxstream { namespace host { diff --git a/host/gl/emulated_egl_window_surface.cpp b/host/gl/emulated_egl_window_surface.cpp index 3759e25dd..34ed7cfc3 100644 --- a/host/gl/emulated_egl_window_surface.cpp +++ b/host/gl/emulated_egl_window_surface.cpp @@ -61,7 +61,7 @@ std::unique_ptr EmulatedEglWindowSurface::create( return surface; } -void EmulatedEglWindowSurface::setColorBuffer(ColorBufferPtr p_colorBuffer) { +void EmulatedEglWindowSurface::setColorBuffer(IColorBufferRef p_colorBuffer) { mAttachedColorBuffer = p_colorBuffer; if (!p_colorBuffer) return; @@ -131,7 +131,11 @@ bool EmulatedEglWindowSurface::flushColorBuffer() { } } - mAttachedColorBuffer->glOpBlitFromCurrentReadBuffer(); + mAttachedColorBuffer->touch(); + auto cbGl = mAttachedColorBuffer->getColorBufferGl(); + if (cbGl) { + cbGl->blitFromCurrentReadBuffer(); + } if (needToSet) { // restore current context/surface @@ -224,10 +228,9 @@ void EmulatedEglWindowSurface::onSave(gfxstream::Stream* stream) const { } std::unique_ptr EmulatedEglWindowSurface::onLoad( - gfxstream::Stream* stream, - EGLDisplay display, - const ColorBufferMap& colorBuffers, - const EmulatedEglContextMap& contexts) { + gfxstream::Stream* stream, EGLDisplay display, + const std::function& colorBufferLookup, + const EmulatedEglContextMap& contexts) { HandleType hndl = stream->getBe32(); HandleType colorBufferHndl = stream->getBe32(); HandleType readCtx = stream->getBe32(); @@ -244,9 +247,8 @@ std::unique_ptr EmulatedEglWindowSurface::onLoad( assert(surface); // fb is already locked by its caller if (colorBufferHndl) { - const auto* colorBufferRef = gfxstream::base::find(colorBuffers, colorBufferHndl); - assert(colorBufferRef); - surface->mAttachedColorBuffer = colorBufferRef->cb; + surface->mAttachedColorBuffer = colorBufferLookup(colorBufferHndl); + assert(surface->mAttachedColorBuffer); } surface->mReadContext = gfxstream::base::findOrDefault(contexts, readCtx); surface->mDrawContext = gfxstream::base::findOrDefault(contexts, drawCtx); diff --git a/host/gl/emulated_egl_window_surface.h b/host/gl/emulated_egl_window_surface.h index bdab48470..40d0482cb 100644 --- a/host/gl/emulated_egl_window_surface.h +++ b/host/gl/emulated_egl_window_surface.h @@ -19,14 +19,15 @@ #include #include +#include #include #include #include -#include "color_buffer.h" -#include "handle.h" -#include "gl/color_buffer_gl.h" -#include "gl/emulated_egl_context.h" +#include "color_buffer_gl.h" +#include "emulated_egl_context.h" +#include "gfxstream/host/color_buffer_interface.h" +#include "gfxstream/host/handle.h" namespace gfxstream { namespace host { @@ -60,12 +61,10 @@ class EmulatedEglWindowSurface { // // IMPORTANT: This automatically resizes the Pbuffer's to the ColorBuffer's // dimensions. Potentially losing pixel values in the process. - void setColorBuffer(ColorBufferPtr p_colorBuffer); + void setColorBuffer(IColorBufferRef p_colorBuffer); // Retrieves a pointer to the attached color buffer. - ColorBuffer* getAttachedColorBuffer() const { - return mAttachedColorBuffer.get(); - } + IColorBuffer* getAttachedColorBuffer() const { return mAttachedColorBuffer.get(); } // Copy the Pbuffer's pixels to the attached color buffer. // Returns true on success, or false on error (e.g. if there is no @@ -99,10 +98,9 @@ class EmulatedEglWindowSurface { void onSave(gfxstream::Stream* stream) const; static std::unique_ptr onLoad( - gfxstream::Stream* stream, - EGLDisplay display, - const ColorBufferMap& colorBuffers, - const EmulatedEglContextMap& contexts); + gfxstream::Stream* stream, EGLDisplay display, + const std::function& colorBufferLookup, + const EmulatedEglContextMap& contexts); HandleType getHndl() const; @@ -114,7 +112,7 @@ class EmulatedEglWindowSurface { bool resize(unsigned int p_width, unsigned int p_height); EGLSurface mSurface = EGL_NO_SURFACE; - ColorBufferPtr mAttachedColorBuffer; + IColorBufferRef mAttachedColorBuffer; EmulatedEglContextPtr mReadContext; EmulatedEglContextPtr mDrawContext; GLuint mWidth = 0; diff --git a/host/gl/emulation_gl.cpp b/host/gl/emulation_gl.cpp index b25ee0293..d6c04efe2 100644 --- a/host/gl/emulation_gl.cpp +++ b/host/gl/emulation_gl.cpp @@ -19,26 +19,80 @@ #include #include -#include "display_surface_gl.h" -#include "gles_version_detector.h" -#include "common/gles_context.h" #include "OpenGLESDispatch/DispatchTables.h" #include "OpenGLESDispatch/EGLDispatch.h" #include "OpenGLESDispatch/GLESv2Dispatch.h" #include "OpenGLESDispatch/OpenGLDispatchLoader.h" -#include "render_thread_info_gl.h" +#include "common/gles_context.h" +#include "display_surface_gl.h" +#include "glestranslator/egl/egl_global_info.h" #include "gfxstream/ThreadAnnotations.h" #include "gfxstream/common/logging.h" +#include "gfxstream/host/color_buffer_interface.h" #include "gfxstream/host/driver_info.h" +#include "gfxstream/host/framework_formats.h" +#include "gfxstream/host/gfxstream_format.h" +#include "gfxstream/host/global_state.h" #include "gfxstream/host/renderer_operations.h" +#include "gfxstream/host/stream_utils.h" #include "gfxstream/misc/StringUtils.h" +#include "gles_version_detector.h" +#include "render-utils/MediaNative.h" +#include "render-utils/RenderLib.h" +#include "render_thread_info_gl.h" +#include "yuv_converter.h" namespace gfxstream { namespace host { namespace gl { namespace { -using gfxstream::host::GfxstreamFormat; +std::optional GetGfxstreamFormat(const FeatureSet& features, + FrameworkFormat format) { + switch (format) { + case FRAMEWORK_FORMAT_NV12: + return GfxstreamFormat::NV12; + case FRAMEWORK_FORMAT_YV12: + return GfxstreamFormat::YV12; + case FRAMEWORK_FORMAT_P010: + return GfxstreamFormat::P010; + case FRAMEWORK_FORMAT_YUV_420_888: { + if (features.Yuv420888ToNv21.enabled()) { + return GfxstreamFormat::NV21; + } else { + return GfxstreamFormat::YV21; + } + } + default: + return std::nullopt; + } +} + +template +static void saveProcOwnedCollection(gfxstream::Stream* stream, const Collection& c) { + const int count = std::count_if( + c.begin(), c.end(), + [](const typename Collection::value_type& pair) { return !pair.second.empty(); }); + stream->putBe32(count); + for (const auto& pair : c) { + if (pair.second.empty()) { + continue; + } + stream->putBe64(pair.first); + saveCollection(stream, pair.second, + [](gfxstream::Stream* s, HandleType h) { s->putBe32(h); }); + } +} + +template +static void loadProcOwnedCollection(gfxstream::Stream* stream, Collection* c) { + loadCollection(stream, c, [](gfxstream::Stream* stream) -> typename Collection::value_type { + const int processId = stream->getBe64(); + typename Collection::mapped_type handles; + loadCollection(stream, &handles, [](gfxstream::Stream* s) { return s->getBe32(); }); + return {processId, std::move(handles)}; + }); +} #ifdef ENABLE_GFXSTREAM_DEBUG @@ -247,12 +301,14 @@ bool EmulationGl::initDispatchers(bool eglOnEgl) { std::unique_ptr EmulationGl::create(uint32_t width, uint32_t height, const gfxstream::host::FeatureSet& features, - bool allowWindowSurface) { + bool allowWindowSurface, + GlobalState* globalState) { std::unique_ptr emulationGl(new EmulationGl()); emulationGl->mFeatures = features; emulationGl->mWidth = width; emulationGl->mHeight = height; + emulationGl->mGlobalState = globalState; emulationGl->mEglDisplay = s_egl.eglGetDisplay(EGL_DEFAULT_DISPLAY); if (emulationGl->mEglDisplay == EGL_NO_DISPLAY) { @@ -597,6 +653,10 @@ EmulationGl::~EmulationGl() { } } + for (auto it : mPlatformEglContexts) { + destroySharedTrivialContext(it.second.context, it.second.surface); + } + if (mEglDisplay != EGL_NO_DISPLAY) { s_egl.eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); if (mEglContext != EGL_NO_CONTEXT) { @@ -743,6 +803,16 @@ ContextHelper* EmulationGl::getColorBufferContextHelper() { return surfaceGl->getContextHelper(); } +ContextHelper* EmulationGl::getPbufferSurfaceContextHelper() const { + if (!mPbufferSurface) { + GFXSTREAM_FATAL("EGL emulation pbuffer surface not available."); + } + const auto* displaySurfaceGl = + reinterpret_cast(mPbufferSurface->getImpl()); + + return displaySurfaceGl->getContextHelper(); +} + std::unique_ptr EmulationGl::createBuffer(uint64_t size, HandleType handle) { return BufferGl::create(size, handle, getColorBufferContextHelper()); } @@ -782,11 +852,9 @@ std::unique_ptr EmulationGl::loadColorBuffer(gfxstream::Stream* s mPixelReadFormats); } -std::unique_ptr EmulationGl::createEmulatedEglContext( - uint32_t emulatedEglConfigIndex, - const EmulatedEglContext* sharedContext, - GLESApi api, - HandleType handle) { +std::unique_ptr EmulationGl::createEmulatedEglContextImpl( + uint32_t emulatedEglConfigIndex, const EmulatedEglContext* sharedContext, GLESApi api, + HandleType handle) { if (!mEmulatedEglConfigs) { GFXSTREAM_ERROR("EmulatedEglConfigs unavailable."); return nullptr; @@ -809,29 +877,75 @@ std::unique_ptr EmulationGl::loadEmulatedEglContext( return EmulatedEglContext::onLoad(stream, mEglDisplay); } -std::unique_ptr EmulationGl::createEmulatedEglFenceSync( - EGLenum type, - int destroyWhenSignaled) { +uint64_t EmulationGl::createEmulatedEglFenceSync(EGLenum type, int destroyWhenSignaled) { + RenderThreadInfoGl* const info = RenderThreadInfoGl::get(); + if (!info) { + GFXSTREAM_FATAL("RenderThreadGL not available."); + } + if (!info->currContext) { + uint32_t syncContext; + uint32_t syncSurface; + createTrivialContext(0, // There is no context to share. + &syncContext, &syncSurface); + bindContext(syncContext, syncSurface, syncSurface); + // This context is then cleaned up when the render thread exits. + } + const bool hasNativeFence = type == EGL_SYNC_NATIVE_FENCE_ANDROID; - return EmulatedEglFenceSync::create(mEglDisplay, - hasNativeFence, - destroyWhenSignaled); + auto sync = EmulatedEglFenceSync::create(mEglDisplay, hasNativeFence, destroyWhenSignaled); + return sync ? (uint64_t)(uintptr_t)sync.release() : 0; +} +HandleType EmulationGl::createEmulatedEglImage(HandleType contextHandle, EGLenum target, + EGLClientBuffer buffer) { + EGLContext eglContext = EGL_NO_CONTEXT; + if (contextHandle) { + auto it = mContexts.find(contextHandle); + if (it != mContexts.end()) { + eglContext = it->second->getEGLContext(); + } else { + GFXSTREAM_ERROR("Failed to find EmulatedEglContext:%d", contextHandle); + return 0; + } + } + auto image = EmulatedEglImage::create(mEglDisplay, eglContext, target, buffer); + if (!image) { + GFXSTREAM_ERROR("Failed to create EmulatedEglImage"); + return 0; + } + + HandleType imageHandle = image->getHandle(); + mImages[imageHandle] = std::move(image); + + RenderThreadInfoGl* tInfo = RenderThreadInfoGl::get(); + uint64_t puid = tInfo->m_puid; + if (puid) { + mProcOwnedEmulatedEglImages[puid].insert(imageHandle); + } + return imageHandle; } -std::unique_ptr EmulationGl::createEmulatedEglImage( - EmulatedEglContext* context, - EGLenum target, - EGLClientBuffer buffer) { - EGLContext eglContext = context ? context->getEGLContext() : EGL_NO_CONTEXT; - return EmulatedEglImage::create(mEglDisplay, eglContext, target, buffer); +bool EmulationGl::destroyEmulatedEglImage(HandleType imageHandle) { + auto imageIt = mImages.find(imageHandle); + if (imageIt == mImages.end()) { + GFXSTREAM_ERROR("Failed to find EmulatedEglImage:%d", imageHandle); + return false; + } + auto& image = imageIt->second; + + EGLBoolean success = image->destroy(); + mImages.erase(imageIt); + + RenderThreadInfoGl* tInfo = RenderThreadInfoGl::get(); + uint64_t puid = tInfo->m_puid; + if (puid) { + mProcOwnedEmulatedEglImages[puid].erase(imageHandle); + } + return (success == EGL_TRUE); } -std::unique_ptr EmulationGl::createEmulatedEglWindowSurface( - uint32_t emulatedConfigIndex, - uint32_t width, - uint32_t height, - HandleType handle) { +std::unique_ptr EmulationGl::createEmulatedEglWindowSurfaceImpl( + uint32_t emulatedConfigIndex, uint32_t width, uint32_t height, HandleType handle) { if (!mEmulatedEglConfigs) { GFXSTREAM_ERROR("EmulatedEglConfigs unavailable."); return nullptr; @@ -849,10 +963,738 @@ std::unique_ptr EmulationGl::createEmulatedEglWindowSu } std::unique_ptr EmulationGl::loadEmulatedEglWindowSurface( - gfxstream::Stream* stream, - const ColorBufferMap& colorBuffers, - const EmulatedEglContextMap& contexts) { - return EmulatedEglWindowSurface::onLoad(stream, mEglDisplay, colorBuffers, contexts); + gfxstream::Stream* stream, const std::function& colorBufferLookup, + const EmulatedEglContextMap& contexts) { + return EmulatedEglWindowSurface::onLoad(stream, mEglDisplay, colorBufferLookup, contexts); +} + +HandleType EmulationGl::createEmulatedEglContext(uint32_t emulatedConfigIndex, + HandleType shareContextHandle, GLESApi api) { + gfxstream::base::AutoWriteLock contextLock(mContextStructureLock); + HandleType handle = mGlobalState->genHandleLocked(); + + EmulatedEglContextPtr shareContext = nullptr; + if (shareContextHandle != 0) { + auto shareContextIt = mContexts.find(shareContextHandle); + if (shareContextIt == mContexts.end()) { + GFXSTREAM_ERROR("Failed to find share EmulatedEglContext:%d", shareContextHandle); + return 0; + } + shareContext = shareContextIt->second; + } + + auto context = + createEmulatedEglContextImpl(emulatedConfigIndex, shareContext.get(), api, handle); + if (!context) { + GFXSTREAM_ERROR("Failed to create EmulatedEglContext."); + return 0; + } + + mContexts[handle] = std::move(context); + + RenderThreadInfoGl* tinfo = RenderThreadInfoGl::get(); + if (!tinfo) { + GFXSTREAM_FATAL("RenderThreadInfoGl not available."); + } + uint64_t puid = tinfo->m_puid; + if (puid) { + mProcOwnedEmulatedEglContexts[puid].insert(handle); + } + return handle; +} + +void EmulationGl::destroyEmulatedEglContext(HandleType contextHandle) { + gfxstream::base::AutoWriteLock contextLock(mContextStructureLock); + auto it = mContexts.find(contextHandle); + if (it == mContexts.end()) { + GFXSTREAM_ERROR("Failed to find EmulatedEglContext:%d", contextHandle); + return; + } + mContexts.erase(it); + + RenderThreadInfoGl* tinfo = RenderThreadInfoGl::get(); + if (!tinfo) { + GFXSTREAM_FATAL("RenderThreadInfoGl not available."); + } + uint64_t puid = tinfo->m_puid; + if (puid) { + auto procIte = mProcOwnedEmulatedEglContexts.find(puid); + if (procIte != mProcOwnedEmulatedEglContexts.end()) { + procIte->second.erase(contextHandle); + } + } else { + tinfo->m_contextSet.erase(contextHandle); + } +} + +HandleType EmulationGl::createEmulatedEglWindowSurface(uint32_t emulatedConfigIndex, uint32_t width, + uint32_t height) { + HandleType handle = mGlobalState->genHandleLocked(); + auto window = createEmulatedEglWindowSurfaceImpl(emulatedConfigIndex, width, height, handle); + if (!window) { + GFXSTREAM_ERROR("Failed to create EmulatedEglWindowSurface."); + return 0; + } + + mWindows[handle] = {std::move(window), 0}; + + RenderThreadInfoGl* info = RenderThreadInfoGl::get(); + if (!info) { + GFXSTREAM_FATAL("RenderThreadInfoGl not available."); + } + + uint64_t puid = info->m_puid; + if (puid) { + mProcOwnedEmulatedEglWindowSurfaces[puid].insert(handle); + } else { + info->m_windowSet.insert(handle); + } + + return handle; +} + +std::vector EmulationGl::destroyEmulatedEglWindowSurface(HandleType surfaceHandle) { + std::vector colorBuffersToCleanUp; + const auto w = mWindows.find(surfaceHandle); + if (w != mWindows.end()) { + RecursiveScopedContextBind bind(getColorBufferContextHelper()); + if (w->second.second != 0) { + colorBuffersToCleanUp.push_back(w->second.second); + } + mWindows.erase(w); + RenderThreadInfoGl* tinfo = RenderThreadInfoGl::get(); + if (!tinfo) { + GFXSTREAM_FATAL("RenderThreadInfoGl not available."); + } + uint64_t puid = tinfo->m_puid; + if (puid) { + auto ite = mProcOwnedEmulatedEglWindowSurfaces.find(puid); + if (ite != mProcOwnedEmulatedEglWindowSurfaces.end()) { + ite->second.erase(surfaceHandle); + } + } else { + tinfo->m_windowSet.erase(surfaceHandle); + } + } + return colorBuffersToCleanUp; +} + +bool EmulationGl::isHandleInUse(HandleType handle) const { + return mContexts.find(handle) != mContexts.end() || mWindows.find(handle) != mWindows.end(); +} + +EmulatedEglContextPtr EmulationGl::getContext(HandleType contextHandle) { + return gfxstream::base::findOrDefault(mContexts, contextHandle); +} + +EmulatedEglWindowSurfacePtr EmulationGl::getWindowSurface(HandleType surfaceHandle) { + return gfxstream::base::findOrDefault(mWindows, surfaceHandle).first; +} + +bool EmulationGl::bindColorBufferToTexture(IColorBuffer* colorBuffer) { + if (!colorBuffer) { + GFXSTREAM_ERROR("Failed to bind to texture: invalid color buffer."); + return false; + } + colorBuffer->touch(); + + auto colorBufferGl = colorBuffer->getColorBufferGl(); + if (!colorBufferGl) { + GFXSTREAM_ERROR("Failed to bind to texture: invalid color buffer gl."); + return false; + } + return colorBufferGl->bindToTexture(); +} + +bool EmulationGl::bindColorBufferToTexture2(IColorBuffer* colorBuffer) { + if (!colorBuffer) { + GFXSTREAM_ERROR("Failed to bind to texture: invalid color buffer."); + return false; + } + colorBuffer->touch(); + + auto colorBufferGl = colorBuffer->getColorBufferGl(); + if (!colorBufferGl) { + GFXSTREAM_ERROR("Failed to bind to texture: invalid color buffer gl."); + return false; + } + return colorBufferGl->bindToTexture2(); +} + +bool EmulationGl::bindColorBufferToRenderbuffer(IColorBuffer* colorBuffer) { + if (!colorBuffer) { + GFXSTREAM_ERROR("Failed to bind to renderbuffer: invalid color buffer."); + return false; + } + colorBuffer->touch(); + + auto colorBufferGl = colorBuffer->getColorBufferGl(); + if (!colorBufferGl) { + GFXSTREAM_ERROR("Failed to bind to renderbuffer: invalid color buffer gl."); + return false; + } + return colorBufferGl->bindToRenderbuffer(); +} + +bool EmulationGl::bindContext(HandleType contextHandle, HandleType drawSurfaceHandle, + HandleType readSurfaceHandle) { + EmulatedEglWindowSurfacePtr draw = nullptr; + EmulatedEglWindowSurfacePtr read = nullptr; + EmulatedEglContextPtr ctx = nullptr; + + if (contextHandle || drawSurfaceHandle || readSurfaceHandle) { + ctx = getContext(contextHandle); + if (!ctx) return false; + + auto drawWindowIt = mWindows.find(drawSurfaceHandle); + if (drawWindowIt == mWindows.end()) { + return false; + } + draw = drawWindowIt->second.first; + + if (readSurfaceHandle != drawSurfaceHandle) { + auto readWindowIt = mWindows.find(readSurfaceHandle); + if (readWindowIt == mWindows.end()) { + return false; + } + read = readWindowIt->second.first; + } else { + read = draw; + } + } + + if (!s_egl.eglMakeCurrent(mEglDisplay, draw ? draw->getEGLSurface() : EGL_NO_SURFACE, + read ? read->getEGLSurface() : EGL_NO_SURFACE, + ctx ? ctx->getEGLContext() : EGL_NO_CONTEXT)) { + GFXSTREAM_ERROR("eglMakeCurrent failed"); + return false; + } + + RenderThreadInfoGl* const tinfo = RenderThreadInfoGl::get(); + if (!tinfo) { + GFXSTREAM_FATAL("RenderThreadGl not available."); + } + + EmulatedEglWindowSurfacePtr bindDraw, bindRead; + if (draw.get() == NULL && read.get() == NULL) { + bindDraw = tinfo->currDrawSurf; + bindRead = tinfo->currReadSurf; + } else { + bindDraw = draw; + bindRead = read; + } + + if (bindDraw.get() != NULL && bindRead.get() != NULL) { + if (bindDraw.get() != bindRead.get()) { + bindDraw->bind(ctx, EmulatedEglWindowSurface::BIND_DRAW); + bindRead->bind(ctx, EmulatedEglWindowSurface::BIND_READ); + } else { + bindDraw->bind(ctx, EmulatedEglWindowSurface::BIND_READDRAW); + } + } + + tinfo->currContext = ctx; + tinfo->currDrawSurf = draw; + tinfo->currReadSurf = read; + if (ctx) { + if (ctx->clientVersion() > GLESApi_CM) + tinfo->m_gl2Dec.setContextData(&ctx->decoderContextData()); + else + tinfo->m_glDec.setContextData(&ctx->decoderContextData()); + } else { + tinfo->m_glDec.setContextData(NULL); + tinfo->m_gl2Dec.setContextData(NULL); + } + return true; +} + +void EmulationGl::preSave(Stream* stream, const gfxstream::ITextureSaverPtr& textureSaver) { + if (s_egl.eglPreSaveContext && s_egl.eglSaveAllImages) { + for (const auto& ctx : mContexts) { + s_egl.eglPreSaveContext(mEglDisplay, ctx.second->getEGLContext(), stream); + } + s_egl.eglSaveAllImages(mEglDisplay, stream, &textureSaver); + } +} + +void EmulationGl::saveContexts(Stream* stream) { + saveCollection(stream, mContexts, [](Stream* s, const EmulatedEglContextMap::value_type& pair) { + pair.second->onSave(s); + }); +} + +void EmulationGl::saveWindowSurfaces(Stream* stream) { + saveCollection(stream, mWindows, + [](Stream* s, const EmulatedEglWindowSurfaceMap::value_type& pair) { + pair.second.first->onSave(s); + s->putBe32(pair.second.second); + }); +} + +void EmulationGl::saveProcOwnedWindowSurfaces(Stream* stream) { + saveProcOwnedCollection(stream, mProcOwnedEmulatedEglWindowSurfaces); +} + +void EmulationGl::saveProcOwnedContexts(Stream* stream) { + saveProcOwnedCollection(stream, mProcOwnedEmulatedEglContexts); +} + +void EmulationGl::saveProcOwnedImages(Stream* stream) { + saveProcOwnedCollection(stream, mProcOwnedEmulatedEglImages); +} + +bool EmulationGl::loadContexts(Stream* stream) { + loadCollection(stream, &mContexts, [this](Stream* stream) -> EmulatedEglContextMap::value_type { + auto context = loadEmulatedEglContext(stream); + auto contextHandle = context ? context->getHndl() : 0; + return {contextHandle, std::move(context)}; + }); + assert(!gfxstream::base::find(mContexts, 0)); + return true; +} + +bool EmulationGl::loadWindowSurfaces( + Stream* stream, const std::function& colorBufferLookup) { + loadCollection( + stream, &mWindows, + [this, &colorBufferLookup](Stream* stream) -> EmulatedEglWindowSurfaceMap::value_type { + auto window = loadEmulatedEglWindowSurface(stream, colorBufferLookup, mContexts); + + HandleType handle = window->getHndl(); + HandleType colorBufferHandle = stream->getBe32(); + return {handle, {std::move(window), colorBufferHandle}}; + }); + return true; +} + +void EmulationGl::loadProcOwnedWindowSurfaces(Stream* stream) { + loadProcOwnedCollection(stream, &mProcOwnedEmulatedEglWindowSurfaces); +} + +void EmulationGl::loadProcOwnedContexts(Stream* stream) { + loadProcOwnedCollection(stream, &mProcOwnedEmulatedEglContexts); +} + +void EmulationGl::loadProcOwnedImages(Stream* stream) { + loadProcOwnedCollection(stream, &mProcOwnedEmulatedEglImages); +} + +void EmulationGl::loadAllImages(Stream* stream, const gfxstream::ITextureLoaderPtr& textureLoader) { + if (s_egl.eglLoadAllImages) { + s_egl.eglLoadAllImages(mEglDisplay, stream, &textureLoader); + } +} + +void EmulationGl::postLoad(Stream* stream) { + if (s_egl.eglPostLoadAllImages) { + s_egl.eglPostLoadAllImages(mEglDisplay, stream); + } +} + +bool EmulationGl::bindColorBufferToWindowSurface(HandleType surfaceHandle, + HandleType colorBufferHandle, + HandleType* outOldColorBufferHandle) { + auto w = mWindows.find(surfaceHandle); + if (w == mWindows.end()) { + return false; + } + + IColorBufferRef cb = nullptr; + if (colorBufferHandle) { + cb = mGlobalState->findColorBuffer(colorBufferHandle); + if (!cb) { + GFXSTREAM_ERROR("bad color buffer handle %d", colorBufferHandle); + return false; + } + } + + w->second.first->setColorBuffer(cb); + *outOldColorBufferHandle = w->second.second; + w->second.second = colorBufferHandle; + return true; +} + +HandleType EmulationGl::getWindowSurfaceColorBufferHandle(HandleType surfaceHandle) const { + auto it = mWindows.find(surfaceHandle); + if (it == mWindows.end()) { + return 0; + } + return it->second.second; +} + +std::vector EmulationGl::cleanupProcGLObjects(uint64_t puid) { + RecursiveScopedContextBind bind(getColorBufferContextHelper()); + std::vector colorBuffersToCleanUp; + + // Clean up window surfaces + auto procWindowsIt = mProcOwnedEmulatedEglWindowSurfaces.find(puid); + if (procWindowsIt != mProcOwnedEmulatedEglWindowSurfaces.end()) { + for (auto whndl : procWindowsIt->second) { + auto w = mWindows.find(whndl); + if (w != mWindows.end()) { + if (w->second.second != 0) { + colorBuffersToCleanUp.push_back(w->second.second); + } + mWindows.erase(w); + } + } + mProcOwnedEmulatedEglWindowSurfaces.erase(procWindowsIt); + } + + // Cleanup render contexts + auto procContextsIt = mProcOwnedEmulatedEglContexts.find(puid); + if (procContextsIt != mProcOwnedEmulatedEglContexts.end()) { + for (auto ctx : procContextsIt->second) { + mContexts.erase(ctx); + } + mProcOwnedEmulatedEglContexts.erase(procContextsIt); + } + + // Cleanup EGLImages + auto procImagesIt = mProcOwnedEmulatedEglImages.find(puid); + if (procImagesIt != mProcOwnedEmulatedEglImages.end()) { + for (auto image : procImagesIt->second) { + mImages.erase(image); + } + mProcOwnedEmulatedEglImages.erase(procImagesIt); + } + return colorBuffersToCleanUp; +} + +void EmulationGl::postSave(Stream* stream) { + if (s_egl.eglPostSaveContext) { + for (const auto& ctx : mContexts) { + s_egl.eglPostSaveContext(mEglDisplay, ctx.second->getEGLContext(), stream); + } + if (mEglContext != EGL_NO_CONTEXT) { + s_egl.eglPostSaveContext(mEglDisplay, mEglContext, stream); + } + } +} + +bool EmulationGl::hasContextsOrWindowSurfaces() const { + return !mContexts.empty() || !mWindows.empty(); +} + +void EmulationGl::clearContextsAndWindowSurfaces() { + mContexts.clear(); + mWindows.clear(); +} + +bool EmulationGl::hasProcOwnedResources() const { + return !mProcOwnedEmulatedEglContexts.empty() || !mProcOwnedEmulatedEglWindowSurfaces.empty() || + !mProcOwnedEmulatedEglImages.empty(); +} + +std::vector EmulationGl::getGLPUIDs() const { + std::vector puids; + for (const auto& pair : mProcOwnedEmulatedEglContexts) { + puids.push_back(pair.first); + } + for (const auto& pair : mProcOwnedEmulatedEglWindowSurfaces) { + if (std::find(puids.begin(), puids.end(), pair.first) == puids.end()) { + puids.push_back(pair.first); + } + } + for (const auto& pair : mProcOwnedEmulatedEglImages) { + if (std::find(puids.begin(), puids.end(), pair.first) == puids.end()) { + puids.push_back(pair.first); + } + } + return puids; +} + +void EmulationGl::drainRenderThreadContexts() { + gfxstream::base::AutoWriteLock contextLock(mContextStructureLock); + RenderThreadInfoGl* const tinfo = RenderThreadInfoGl::get(); + if (!tinfo) { + GFXSTREAM_FATAL("RenderThreadGL not available."); + } + for (const HandleType contextHandle : tinfo->m_contextSet) { + mContexts.erase(contextHandle); + } + tinfo->m_contextSet.clear(); +} + +void EmulationGl::drainRenderThreadSurfaces() { + RenderThreadInfoGl* const tinfo = RenderThreadInfoGl::get(); + if (!tinfo) { + GFXSTREAM_FATAL("RenderThreadGL not available."); + } + RecursiveScopedContextBind bind(getColorBufferContextHelper()); + for (const HandleType winHandle : tinfo->m_windowSet) { + const auto winIt = mWindows.find(winHandle); + if (winIt != mWindows.end()) { + if (winIt->second.second != 0) { + mGlobalState->closeColorBufferByWindow(winIt->second.second); + } + mWindows.erase(winIt); + } + } + tinfo->m_windowSet.clear(); +} + +bool EmulationGl::flushEmulatedEglWindowSurfaceColorBuffer(HandleType surfaceHandle) { + auto it = mWindows.find(surfaceHandle); + if (it == mWindows.end()) { + GFXSTREAM_ERROR("flushEmulatedEglWindowSurfaceColorBuffer: window handle %#x not found", + surfaceHandle); + return false; + } + it->second.first->flushColorBuffer(); + return true; +} + +void EmulationGl::createTrivialContext(HandleType shared, HandleType* contextOut, + HandleType* surfOut) { + assert(contextOut); + assert(surfOut); + + *contextOut = createEmulatedEglContext(0, shared, GLESApi_2); + *surfOut = createEmulatedEglWindowSurface(0, 1, 1); +} + +void EmulationGl::createSharedTrivialContext(EGLContext* contextOut, EGLSurface* surfOut) { + assert(contextOut); + assert(surfOut); + + if (mEglConfig == EGL_NO_CONFIG) { + GFXSTREAM_FATAL("GL/EGL emulation has not chosen a config."); + } + + int maj, min; + get_gfxstream_gles_version(&maj, &min); + + const EGLint contextAttribs[] = {EGL_CONTEXT_MAJOR_VERSION_KHR, maj, + EGL_CONTEXT_MINOR_VERSION_KHR, min, EGL_NONE}; + + *contextOut = s_egl.eglCreateContext(mEglDisplay, mEglConfig, mEglContext, contextAttribs); + + const EGLint pbufAttribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE}; + + *surfOut = s_egl.eglCreatePbufferSurface(mEglDisplay, mEglConfig, pbufAttribs); +} + +void EmulationGl::destroySharedTrivialContext(EGLContext context, EGLSurface surface) { + if (mEglDisplay != EGL_NO_DISPLAY) { + s_egl.eglDestroyContext(mEglDisplay, context); + s_egl.eglDestroySurface(mEglDisplay, surface); + } +} + +bool EmulationGl::setEmulatedEglWindowSurfaceColorBuffer(HandleType surfaceHandle, + HandleType colorBufferHandle) { + HandleType oldColorBuffer = 0; + if (!bindColorBufferToWindowSurface(surfaceHandle, colorBufferHandle, &oldColorBuffer)) { + return false; + } + + if (colorBufferHandle) { + mGlobalState->openColorBufferByWindow(colorBufferHandle); + } + + if (oldColorBuffer) { + mGlobalState->closeColorBufferByWindow(oldColorBuffer); + } + + return true; +} + +void* EmulationGl::platformCreateSharedEglContext() { + EGLContext context = 0; + EGLSurface surface = 0; + createSharedTrivialContext(&context, &surface); + + void* underlyingContext = s_egl.eglGetNativeContextANDROID(mEglDisplay, context); + if (!underlyingContext) { + GFXSTREAM_ERROR("Error: Underlying egl backend could not produce a native EGL context."); + return nullptr; + } + + mPlatformEglContexts[underlyingContext] = {context, surface}; + +#if defined(__QNX__) + EGLDisplay currDisplay = eglGetCurrentDisplay(); + EGLSurface currRead = eglGetCurrentSurface(EGL_READ); + EGLSurface currDraw = eglGetCurrentSurface(EGL_DRAW); + EGLSurface currContext = eglGetCurrentContext(); + // Make this context current to ensure thread-state is initialized + s_egl.eglMakeCurrent(mEglDisplay, surface, surface, context); + // Revert back to original state + s_egl.eglMakeCurrent(currDisplay, currRead, currDraw, currContext); +#endif + + return underlyingContext; +} + +bool EmulationGl::platformDestroySharedEglContext(void* underlyingContext) { + auto it = mPlatformEglContexts.find(underlyingContext); + if (it == mPlatformEglContexts.end()) { + GFXSTREAM_ERROR( + "Error: Could not find underlying egl context %p (perhaps already destroyed?)", + underlyingContext); + return false; + } + + destroySharedTrivialContext(it->second.context, it->second.surface); + + mPlatformEglContexts.erase(it); + + return true; +} + +void EmulationGl::createYUVTextures(uint32_t type, uint32_t count, int width, int height, + uint32_t* output) { + auto formatOpt = GetGfxstreamFormat(mFeatures, static_cast(type)); + if (!formatOpt) { + GFXSTREAM_ERROR("Unsupported framework format %d", type); + return; + } + auto format = *formatOpt; + + auto contextHelper = getPbufferSurfaceContextHelper(); + if (!contextHelper) { + // This should not be called in vulkan-only mode + GFXSTREAM_ERROR("%s: invalid pbuffer surface context", __func__); + return; + } + RecursiveScopedContextBind bind(contextHelper); + if (!bind.isOk()) { + GFXSTREAM_ERROR("%s: could not bind context helper", __func__); + return; + } + for (uint32_t i = 0; i < count; ++i) { + if (format == GfxstreamFormat::NV12 || format == GfxstreamFormat::NV21) { + YUVConverter::createYUVGLTex(GL_TEXTURE0, width, height, format, YuvPlane::Y, + &output[2 * i]); + YUVConverter::createYUVGLTex(GL_TEXTURE1, width / 2, height / 2, format, YuvPlane::UV, + &output[2 * i + 1]); + } else if (format == GfxstreamFormat::YV12 || format == GfxstreamFormat::YV21) { + YUVConverter::createYUVGLTex(GL_TEXTURE0, width, height, format, YuvPlane::Y, + &output[3 * i]); + YUVConverter::createYUVGLTex(GL_TEXTURE1, width / 2, height / 2, format, YuvPlane::U, + &output[3 * i + 1]); + YUVConverter::createYUVGLTex(GL_TEXTURE2, width / 2, height / 2, format, YuvPlane::V, + &output[3 * i + 2]); + } + } +} + +void EmulationGl::destroyYUVTextures(uint32_t type, uint32_t count, uint32_t* textures) { + auto formatOpt = GetGfxstreamFormat(mFeatures, static_cast(type)); + if (!formatOpt) { + GFXSTREAM_ERROR("Unsupported framework format %d", type); + return; + } + auto format = *formatOpt; + + RecursiveScopedContextBind bind(getPbufferSurfaceContextHelper()); + if (format == GfxstreamFormat::NV12 || format == GfxstreamFormat::NV21) { + s_gles2.glDeleteTextures(2 * count, textures); + } else if (format == GfxstreamFormat::YV12 || format == GfxstreamFormat::YV21) { + s_gles2.glDeleteTextures(3 * count, textures); + } +} + +void EmulationGl::updateYUVTextures(uint32_t type, uint32_t* textures, void* privData, void* func) { + auto formatOpt = GetGfxstreamFormat(mFeatures, static_cast(type)); + if (!formatOpt) { + GFXSTREAM_ERROR("Unsupported framework format %d", type); + return; + } + auto format = *formatOpt; + + RecursiveScopedContextBind bind(getPbufferSurfaceContextHelper()); + + yuv_updater_t updater = (yuv_updater_t)func; + uint32_t gtextures[3] = {0, 0, 0}; + + if (format == GfxstreamFormat::NV12 || format == GfxstreamFormat::NV21) { + gtextures[0] = s_gles2.glGetGlobalTexName(textures[0]); + gtextures[1] = s_gles2.glGetGlobalTexName(textures[1]); + } else if (format == GfxstreamFormat::YV12 || format == GfxstreamFormat::YV21) { + gtextures[0] = s_gles2.glGetGlobalTexName(textures[0]); + gtextures[1] = s_gles2.glGetGlobalTexName(textures[1]); + gtextures[2] = s_gles2.glGetGlobalTexName(textures[2]); + } + +#ifdef __APPLE__ + EGLContext prevContext = s_egl.eglGetCurrentContext(); + auto mydisp = EglGlobalInfo::getInstance()->getDisplayFromDisplayType(EGL_DEFAULT_DISPLAY); + void* nativecontext = mydisp->getLowLevelContext(prevContext); + struct MediaNativeCallerData callerdata; + callerdata.ctx = nativecontext; + callerdata.converter = nsConvertVideoFrameToNV12Textures; + void* pcallerdata = &callerdata; +#else + void* pcallerdata = nullptr; +#endif + + updater(privData, type, gtextures, pcallerdata); +} + +void EmulationGl::drainRenderThreadResources() { + bindContext(0, 0, 0); + drainRenderThreadSurfaces(); + drainRenderThreadContexts(); + if (!s_egl.eglReleaseThread()) { + GFXSTREAM_ERROR("Error: RenderThread failed to eglReleaseThread()"); + } +} + +void EmulationGl::fillGlesUsages(android_studio::EmulatorGLESUsages* usages) { + if (s_egl.eglFillUsages) { + s_egl.eglFillUsages(usages); + } +} + +bool EmulationGl::getRenderOpt(gfxstream::RenderOpt* opt) const { + if (!opt) { + return false; + } + opt->display = mEglDisplay; + opt->config = mEglConfig; + + if (!mWindowSurface) { + opt->surface = EGL_NO_SURFACE; + } else { + const auto* displaySurfaceGl = + reinterpret_cast(mWindowSurface->getImpl()); + opt->surface = displaySurfaceGl->getSurface(); + } + + return (opt->display && opt->surface && opt->config); +} + +EGLContext EmulationGl::getGlobalEGLContext() const { + if (!mPbufferSurface) { + GFXSTREAM_FATAL("FrameBuffer pbuffer surface not available."); + } + const auto* displaySurfaceGl = + reinterpret_cast(mPbufferSurface->getImpl()); + return displaySurfaceGl->getContextForShareContext(); +} + +void EmulationGl::swapTexturesAndUpdateColorBuffer(IColorBuffer* colorBuffer, uint32_t format, + uint32_t type, uint32_t texturesType, + uint32_t* textures) { + auto texturesFormatOpt = GetGfxstreamFormat(mFeatures, (FrameworkFormat)texturesType); + if (!texturesFormatOpt) { + GFXSTREAM_ERROR("Unsupported framework format %d", texturesType); + return; + } + auto texturesFormat = *texturesFormatOpt; + + ColorBufferGl* colorBufferGl = colorBuffer->getColorBufferGl(); + if (!colorBufferGl) { + return; + } + + colorBufferGl->swapYUVTextures(texturesFormat, textures); + colorBufferGl->subUpdate(0, 0, colorBuffer->getWidth(), colorBuffer->getHeight(), + texturesFormat, nullptr); + + colorBuffer->flushFromBackend(Backend::GL); } } // namespace gl diff --git a/host/gl/emulation_gl.h b/host/gl/emulation_gl.h index 62f5fd159..4b2f9333b 100644 --- a/host/gl/emulation_gl.h +++ b/host/gl/emulation_gl.h @@ -20,14 +20,25 @@ #include #include +#include +#include #include #include #include #include +namespace android_studio { +class EmulatorGLESUsages; +} + +namespace gfxstream { +struct RenderOpt; +} + +#include "OpenGLESDispatch/EGLDispatch.h" +#include "OpenGLESDispatch/GLESv2Dispatch.h" #include "buffer_gl.h" #include "color_buffer_gl.h" -#include "compositor.h" #include "compositor_gl.h" #include "context_helper.h" #include "display_gl.h" @@ -36,26 +47,24 @@ #include "emulated_egl_fence_sync.h" #include "emulated_egl_image.h" #include "emulated_egl_window_surface.h" -#include "OpenGLESDispatch/EGLDispatch.h" -#include "OpenGLESDispatch/GLESv2Dispatch.h" -#include "pixel_read_formats.h" -#include "readback_worker_gl.h" -#include "texture_draw.h" -#include "gfxstream/host/features.h" +#include "gfxstream/host/color_buffer_interface.h" +#include "gfxstream/host/compositor.h" #include "gfxstream/host/display.h" #include "gfxstream/host/display_surface.h" +#include "gfxstream/host/display_surface_user.h" +#include "gfxstream/host/features.h" +#include "gfxstream/host/framework_formats.h" #include "gfxstream/host/gfxstream_format.h" #include "gfxstream/host/gl_enums.h" +#include "gfxstream/host/global_state.h" +#include "gfxstream/synchronization/Lock.h" +#include "pixel_read_formats.h" +#include "readback_worker_gl.h" #include "render-utils/stream.h" +#include "texture_draw.h" #define EGL_NO_CONFIG ((EGLConfig)0) -namespace gfxstream { -namespace host { -class FrameBuffer; -} // namespace host -} // namespace gfxstream - namespace gfxstream { namespace host { namespace gl { @@ -64,8 +73,8 @@ class EmulationGl { public: static bool initDispatchers(bool eglOnEgl); static std::unique_ptr create(uint32_t width, uint32_t height, - const FeatureSet& features, - bool allowWindowSurface); + const FeatureSet& features, bool allowWindowSurface, + GlobalState* globalState); ~EmulationGl(); @@ -105,6 +114,9 @@ class EmulationGl { CompositorGl* getCompositor() { return mCompositorGl.get(); } DisplayGl* getDisplay() { return mDisplayGl.get(); } + EGLDisplay getEglDisplay() const { return mEglDisplay; } + DisplaySurface* getPbufferSurface() const { return mPbufferSurface.get(); } + TextureDraw* getTextureDraw() const { return mTextureDraw.get(); } ReadbackWorkerGl* getReadbackWorker() { return mReadbackWorkerGl.get(); } @@ -123,87 +135,167 @@ class EmulationGl { std::unique_ptr loadColorBuffer(Stream* stream); - std::unique_ptr createEmulatedEglContext( - uint32_t emulatedEglConfigIndex, - const EmulatedEglContext* shareContext, - GLESApi api, - HandleType handle); + HandleType createEmulatedEglContext(uint32_t emulatedConfigIndex, HandleType shareContextHandle, + GLESApi api); + + void destroyEmulatedEglContext(HandleType contextHandle); + + HandleType createEmulatedEglWindowSurface(uint32_t emulatedConfigIndex, uint32_t width, + uint32_t height); + + std::vector destroyEmulatedEglWindowSurface(HandleType surfaceHandle); + + bool isHandleInUse(HandleType handle) const; + + EmulatedEglContextPtr getContext(HandleType contextHandle); + EmulatedEglWindowSurfacePtr getWindowSurface(HandleType surfaceHandle); + + uint64_t createEmulatedEglFenceSync(EGLenum type, int destroyWhenSignaled); - std::unique_ptr loadEmulatedEglContext( - Stream* stream); + HandleType createEmulatedEglImage(HandleType contextHandle, EGLenum target, + EGLClientBuffer buffer); - std::unique_ptr createEmulatedEglFenceSync( - EGLenum type, - int destroyWhenSignaled); + bool destroyEmulatedEglImage(HandleType imageHandle); - std::unique_ptr createEmulatedEglImage( - EmulatedEglContext* context, - EGLenum target, - EGLClientBuffer buffer); + std::unique_ptr createFakeWindowSurface(); + + bool bindColorBufferToTexture(IColorBuffer* colorBuffer); + bool bindColorBufferToTexture2(IColorBuffer* colorBuffer); + bool bindColorBufferToRenderbuffer(IColorBuffer* colorBuffer); + bool bindContext(HandleType contextHandle, HandleType drawSurfaceHandle, + HandleType readSurfaceHandle); + bool bindColorBufferToWindowSurface(HandleType surfaceHandle, HandleType colorBufferHandle, + HandleType* outOldColorBufferHandle); + HandleType getWindowSurfaceColorBufferHandle(HandleType surfaceHandle) const; + + void preSave(Stream* stream, const gfxstream::ITextureSaverPtr& textureSaver); + void postSave(Stream* stream); + void saveContexts(Stream* stream); + void saveWindowSurfaces(Stream* stream); + void saveProcOwnedWindowSurfaces(Stream* stream); + void saveProcOwnedContexts(Stream* stream); + void saveProcOwnedImages(Stream* stream); + + bool loadContexts(Stream* stream); + bool loadWindowSurfaces(Stream* stream, + const std::function& colorBufferLookup); + void loadProcOwnedWindowSurfaces(Stream* stream); + void loadProcOwnedContexts(Stream* stream); + void loadProcOwnedImages(Stream* stream); + void loadAllImages(Stream* stream, const gfxstream::ITextureLoaderPtr& textureLoader); + void postLoad(Stream* stream); + std::vector cleanupProcGLObjects(uint64_t puid); + bool hasContextsOrWindowSurfaces() const; + void clearContextsAndWindowSurfaces(); + bool hasProcOwnedResources() const; + std::vector getGLPUIDs() const; + void drainRenderThreadContexts(); + void drainRenderThreadSurfaces(); + void drainRenderThreadResources(); + bool flushEmulatedEglWindowSurfaceColorBuffer(HandleType surfaceHandle); + void fillGlesUsages(android_studio::EmulatorGLESUsages* usages); + bool getRenderOpt(gfxstream::RenderOpt* opt) const; + ContextHelper* getPbufferSurfaceContextHelper() const; + EGLContext getGlobalEGLContext() const; + + void lockContextStructureRead() { mContextStructureLock.lockRead(); } + void unlockContextStructureRead() { mContextStructureLock.unlockRead(); } + + void createTrivialContext(HandleType shared, HandleType* contextOut, HandleType* surfOut); + void createSharedTrivialContext(EGLContext* contextOut, EGLSurface* surfOut); + void destroySharedTrivialContext(EGLContext context, EGLSurface surface); + bool setEmulatedEglWindowSurfaceColorBuffer(HandleType surfaceHandle, + HandleType colorBufferHandle); + void* platformCreateSharedEglContext(); + bool platformDestroySharedEglContext(void* underlyingContext); + + void createYUVTextures(uint32_t type, uint32_t count, int width, int height, uint32_t* output); + void destroyYUVTextures(uint32_t type, uint32_t count, uint32_t* textures); + void updateYUVTextures(uint32_t type, uint32_t* textures, void* privData, void* func); + void swapTexturesAndUpdateColorBuffer(IColorBuffer* colorBuffer, uint32_t format, uint32_t type, + uint32_t texturesType, uint32_t* textures); - std::unique_ptr createEmulatedEglWindowSurface( - uint32_t emulatedConfigIndex, - uint32_t width, - uint32_t height, + private: + EmulationGl() = default; + + std::unique_ptr createEmulatedEglContextImpl( + uint32_t emulatedEglConfigIndex, const EmulatedEglContext* shareContext, GLESApi api, HandleType handle); + std::unique_ptr loadEmulatedEglContext(Stream* stream); + + std::unique_ptr createEmulatedEglWindowSurfaceImpl( + uint32_t emulatedConfigIndex, uint32_t width, uint32_t height, HandleType handle); + std::unique_ptr loadEmulatedEglWindowSurface( - Stream* stream, - const ColorBufferMap& colorBuffers, + Stream* stream, const std::function& colorBufferLookup, const EmulatedEglContextMap& contexts); - std::unique_ptr createFakeWindowSurface(); + ContextHelper* getColorBufferContextHelper(); - private: - // TODO(b/233939967): Remove this after fully transitioning to EmulationGl. - friend class ::gfxstream::host::FrameBuffer; + FeatureSet mFeatures; + + EGLDisplay mEglDisplay = EGL_NO_DISPLAY; + EGLint mEglVersionMajor = 0; + EGLint mEglVersionMinor = 0; + std::string mEglVendor; + std::unordered_set mEglExtensions; + EGLConfig mEglConfig = EGL_NO_CONFIG; - EmulationGl() = default; + // The "global" context that all other contexts are shared with. + EGLContext mEglContext = EGL_NO_CONTEXT; - ContextHelper* getColorBufferContextHelper(); + // Used for ColorBuffer ops. + std::unique_ptr mPbufferSurface; - FeatureSet mFeatures; + // Used for Composition and Display ops. + std::unique_ptr mWindowSurface; - EGLDisplay mEglDisplay = EGL_NO_DISPLAY; - EGLint mEglVersionMajor = 0; - EGLint mEglVersionMinor = 0; - std::string mEglVendor; - std::unordered_set mEglExtensions; - EGLConfig mEglConfig = EGL_NO_CONFIG; + GLint mGlesVersionMajor = 0; + GLint mGlesVersionMinor = 0; + GLESDispatchMaxVersion mGlesDispatchMaxVersion = GLES_DISPATCH_MAX_VERSION_2; + std::string mGlesVendor; + std::string mGlesRenderer; + std::string mGlesVersion; + std::string mGlesExtensions; + std::optional mGlesDeviceUuid; + bool mGlesVulkanInteropSupported = false; - // The "global" context that all other contexts are shared with. - EGLContext mEglContext = EGL_NO_CONTEXT; + std::unique_ptr mEmulatedEglConfigs; - // Used for ColorBuffer ops. - std::unique_ptr mPbufferSurface; + bool mFastBlitSupported = false; - // Used for Composition and Display ops. - std::unique_ptr mWindowSurface; + std::unique_ptr mCompositorGl; + std::unique_ptr mDisplayGl; + std::unique_ptr mReadbackWorkerGl; - GLint mGlesVersionMajor = 0; - GLint mGlesVersionMinor = 0; - GLESDispatchMaxVersion mGlesDispatchMaxVersion = GLES_DISPATCH_MAX_VERSION_2; - std::string mGlesVendor; - std::string mGlesRenderer; - std::string mGlesVersion; - std::string mGlesExtensions; - std::optional mGlesDeviceUuid; - bool mGlesVulkanInteropSupported = false; + std::unique_ptr mTextureDraw; - std::unique_ptr mEmulatedEglConfigs; + PixelReadFormats mPixelReadFormats; - bool mFastBlitSupported = false; + uint32_t mWidth = 0; + uint32_t mHeight = 0; - std::unique_ptr mCompositorGl; - std::unique_ptr mDisplayGl; - std::unique_ptr mReadbackWorkerGl; + GlobalState* mGlobalState = nullptr; - std::unique_ptr mTextureDraw; + EmulatedEglContextMap mContexts; + EmulatedEglWindowSurfaceMap mWindows; + using ProcOwnedEmulatedEglContexts = std::unordered_map; + ProcOwnedEmulatedEglContexts mProcOwnedEmulatedEglContexts; + using ProcOwnedEmulatedEglWindowSurfaces = + std::unordered_map; + ProcOwnedEmulatedEglWindowSurfaces mProcOwnedEmulatedEglWindowSurfaces; + EmulatedEglImageMap mImages; + using ProcOwnedEmulatedEglImages = std::unordered_map; + ProcOwnedEmulatedEglImages mProcOwnedEmulatedEglImages; - PixelReadFormats mPixelReadFormats; + struct PlatformEglContextInfo { + EGLContext context; + EGLSurface surface; + }; + std::unordered_map mPlatformEglContexts; - uint32_t mWidth = 0; - uint32_t mHeight = 0; + gfxstream::base::ReadWriteLock mContextStructureLock; }; } // namespace gl diff --git a/host/gl/gles1_dec/BUILD.bazel b/host/gl/gles1_dec/BUILD.bazel index 1f4168ded..6f5f0b105 100644 --- a/host/gl/gles1_dec/BUILD.bazel +++ b/host/gl/gles1_dec/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -16,6 +16,7 @@ cc_library( hdrs = glob(["*.h"]), copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ "//common/base:gfxstream_common_base", "//common/logging:gfxstream_common_logging", diff --git a/host/gl/gles2_dec/BUILD.bazel b/host/gl/gles2_dec/BUILD.bazel index 9af66cfa1..d9c131204 100644 --- a/host/gl/gles2_dec/BUILD.bazel +++ b/host/gl/gles2_dec/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -16,6 +16,7 @@ cc_library( hdrs = glob(["*.h"]), copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ "//common/base:gfxstream_common_base", "//common/logging:gfxstream_common_logging", diff --git a/host/gl/gles2_dec/gles_v2_decoder.cpp b/host/gl/gles2_dec/gles_v2_decoder.cpp index 4f43038dc..fe2bacb72 100644 --- a/host/gl/gles2_dec/gles_v2_decoder.cpp +++ b/host/gl/gles2_dec/gles_v2_decoder.cpp @@ -27,6 +27,7 @@ #include #include +#include "gfxstream/host/address_space_operations.h" #include "gfxstream/host/dma_device.h" #include "gfxstream/host/vm_operations.h" #include "gfxstream/synchronization/Lock.h" @@ -452,15 +453,14 @@ void GLESv2Decoder::s_glUnmapBufferDMA(void* self, GLenum target, GLintptr offse static std::pair align_pointer_size(void* ptr, GLsizeiptr length) { - constexpr size_t kPageBits = 12; - constexpr size_t kPageSize = 1u << kPageBits; - constexpr size_t kPageOffsetMask = kPageSize - 1; + const size_t page_size = gfxstream::host::get_gfxstream_guest_page_size(); + const size_t page_offset_mask = page_size - 1; uintptr_t addr = reinterpret_cast(ptr); - uintptr_t page_offset = addr & kPageOffsetMask; + uintptr_t page_offset = addr & page_offset_mask; return { reinterpret_cast(addr - page_offset), - ((length + page_offset + kPageSize - 1) >> kPageBits) << kPageBits + (GLsizeiptr)((length + page_offset + page_size - 1) & ~page_offset_mask) }; } diff --git a/host/gl/glestranslator/common/Android.bp b/host/gl/glestranslator/common/Android.bp index 3862d6380..dfec95508 100644 --- a/host/gl/glestranslator/common/Android.bp +++ b/host/gl/glestranslator/common/Android.bp @@ -40,11 +40,9 @@ cc_library_static { "libgfxstream_host_compressedtextures", "libgfxstream_host_library", "libgfxstream_common_logging", - "libgfxstream_host_snapshot", ], export_static_lib_headers: [ "libgfxstream_etc", - "libgfxstream_host_snapshot", ], srcs: [ "rgtc.cpp", diff --git a/host/gl/glestranslator/common/BUILD.bazel b/host/gl/glestranslator/common/BUILD.bazel index de7ad2bbf..f88e89f67 100644 --- a/host/gl/glestranslator/common/BUILD.bazel +++ b/host/gl/glestranslator/common/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -12,14 +12,15 @@ cc_library( copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, includes = ["include"], + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ "//common/base:gfxstream_common_base", "//common/etc:gfxstream_etc", "//common/logging:gfxstream_common_logging", "//host:gfxstream_backend_headers", + "//host/common:gfxstream_host_common", "//host/decoder_common:gfxstream_host_decoder_common", "//host/gl/OpenGLESDispatch:gfxstream_host_openglesdispatch_headers", - "//host/snapshot:gfxstream_host_snapshot", "//third_party/opengl:gfxstream_egl_headers", "//third_party/opengl:gfxstream_gles2_headers", "//third_party/opengl:gfxstream_gles3_headers", @@ -55,6 +56,7 @@ cc_library( "-Wno-extern-c-compat", ], defines = GFXSTREAM_HOST_DEFINES, + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ "//common/base:gfxstream_common_base", "//common/etc:gfxstream_etc", diff --git a/host/gl/glestranslator/common/CMakeLists.txt b/host/gl/glestranslator/common/CMakeLists.txt index 76e5bd889..d72eb787e 100644 --- a/host/gl/glestranslator/common/CMakeLists.txt +++ b/host/gl/glestranslator/common/CMakeLists.txt @@ -51,7 +51,6 @@ target_link_libraries( gfxstream_host_common gfxstream_host_compressed_textures gfxstream_host_library - gfxstream_host_snapshot.headers gfxstream_opengl_headers gfxstream_openglesdispatch PRIVATE diff --git a/host/gl/glestranslator/common/gles_context.cpp b/host/gl/glestranslator/common/gles_context.cpp index 10aedb1a1..df539a4d5 100644 --- a/host/gl/glestranslator/common/gles_context.cpp +++ b/host/gl/glestranslator/common/gles_context.cpp @@ -364,9 +364,15 @@ bool GLEScontext::vertexAttributesBufferBacked() { const auto& info = m_currVaoState.attribInfo_const(); for (uint32_t i = 0; i < kMaxVertexAttributes; ++i) { const auto& pointerInfo = info[i]; - if (pointerInfo.isEnable() && - !m_currVaoState.bufferBindings()[pointerInfo.getBindingIndex()].buffer) { - return false; + if (pointerInfo.isEnable()) { + const auto bufferBindingIndex = pointerInfo.getBindingIndex(); + const auto& vaoBindings = m_currVaoState.bufferBindings(); + if (bufferBindingIndex >= vaoBindings.size()) { + return false; + } + if (!vaoBindings[bufferBindingIndex].buffer) { + return false; + } } } diff --git a/host/gl/glestranslator/common/include/common/saveable_texture.h b/host/gl/glestranslator/common/include/common/saveable_texture.h index 03da73678..be1a23dfc 100644 --- a/host/gl/glestranslator/common/include/common/saveable_texture.h +++ b/host/gl/glestranslator/common/include/common/saveable_texture.h @@ -22,7 +22,7 @@ #include #include "render-utils/stream.h" -#include "snapshot/LazySnapshotObj.h" +#include "gfxstream/host/lazy_snapshot_object.h" #include "common/named_object.h" #include "common/texture_data.h" #include "common/translator_ifaces.h" diff --git a/host/gl/glestranslator/common/meson.build b/host/gl/glestranslator/common/meson.build index 0eb196992..c838d6e86 100644 --- a/host/gl/glestranslator/common/meson.build +++ b/host/gl/glestranslator/common/meson.build @@ -39,7 +39,6 @@ lib_gl_common = static_library( inc_host_decoder_common, inc_host_library, inc_common_logging, - inc_host_snapshot, inc_include, inc_stream_servers, ], diff --git a/host/gl/glestranslator/egl/BUILD.bazel b/host/gl/glestranslator/egl/BUILD.bazel index 25899ad36..c952cbc54 100644 --- a/host/gl/glestranslator/egl/BUILD.bazel +++ b/host/gl/glestranslator/egl/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library", "objc_library") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -64,6 +64,7 @@ cc_library( copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, includes = ["glestranslator/egl"], + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ "//common/base:gfxstream_common_base", "//host:gfxstream_backend_headers", @@ -139,6 +140,7 @@ cc_library( "-Wno-return-type-c-linkage", ], defines = GFXSTREAM_HOST_DEFINES, + linkopts = GFXSTREAM_HOST_LINKOPTS, textual_hdrs = [ "client_api_exts.in", ], @@ -150,7 +152,6 @@ cc_library( "//common/logging:gfxstream_common_logging", "//common/utils:gfxstream_common_utils", "//host:gfxstream_backend_headers", - "//host:gfxstream_host_headers", "//host/common:gfxstream_host_common", "//host/decoder_common:gfxstream_host_decoder_common", "//host/gl/glestranslator/common:gfxstream_glestranslator_common", diff --git a/host/gl/glestranslator/egl/egl_global_info.cpp b/host/gl/glestranslator/egl/egl_global_info.cpp index 03acc2259..7056a7920 100644 --- a/host/gl/glestranslator/egl/egl_global_info.cpp +++ b/host/gl/glestranslator/egl/egl_global_info.cpp @@ -25,7 +25,7 @@ namespace { -static EGLBoolean sEgl2Egl = false; +[[maybe_unused]] static EGLBoolean sEgl2Egl = false; static EglGlobalInfo* sSingleton(bool nullEgl = false) { static EglGlobalInfo* i = new EglGlobalInfo(nullEgl); diff --git a/host/gl/glestranslator/egl/meson.build b/host/gl/glestranslator/egl/meson.build index 683d36f2a..aa89d41b2 100644 --- a/host/gl/glestranslator/egl/meson.build +++ b/host/gl/glestranslator/egl/meson.build @@ -57,29 +57,28 @@ lib_egl_translator = static_library( objcpp_args: egl_cpp_args + gfxstream_host_args, dependencies: egl_deps, include_directories: [ - inc_host_decoder_common, inc_common_base, + inc_common_logging, inc_common_utils, inc_etc, inc_gfxstream_server, inc_gl_common, inc_gl_openglesdispatch, inc_host_common, + inc_host_decoder_common, inc_host_library, - inc_common_logging, - inc_host_snapshot, inc_include, inc_opengl_headers, inc_stream_servers, inc_x11_headers, ], link_with: [ - lib_host_decoder_common, lib_common_base, + lib_common_logging, lib_common_utils, lib_gl_common, lib_host_common, + lib_host_decoder_common, lib_host_library, - lib_common_logging, ], ) diff --git a/host/gl/glestranslator/gles_cm/BUILD.bazel b/host/gl/glestranslator/gles_cm/BUILD.bazel index cc8dd020d..6faeedfc0 100644 --- a/host/gl/glestranslator/gles_cm/BUILD.bazel +++ b/host/gl/glestranslator/gles_cm/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -19,6 +19,7 @@ cc_library( "-Wno-extern-c-compat", ], defines = GFXSTREAM_HOST_DEFINES, + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ "//common/base:gfxstream_common_base", "//common/logging:gfxstream_common_logging", diff --git a/host/gl/glestranslator/gles_cm/CMakeLists.txt b/host/gl/glestranslator/gles_cm/CMakeLists.txt index af021062a..19e81a74b 100644 --- a/host/gl/glestranslator/gles_cm/CMakeLists.txt +++ b/host/gl/glestranslator/gles_cm/CMakeLists.txt @@ -36,7 +36,6 @@ target_link_libraries( gfxstream_common_logging gfxstream_host_common gfxstream_host_decoder_common - gfxstream_host_snapshot.headers gfxstream_opengl_headers ) target_include_directories( diff --git a/host/gl/glestranslator/gles_cm/meson.build b/host/gl/glestranslator/gles_cm/meson.build index b7e882ce9..55a993746 100644 --- a/host/gl/glestranslator/gles_cm/meson.build +++ b/host/gl/glestranslator/gles_cm/meson.build @@ -15,20 +15,19 @@ lib_glescm_translator = static_library( cpp_args: gfxstream_host_args, include_directories: [ inc_common_base, + inc_common_logging, inc_etc, inc_gfxstream_server, inc_gl_common, inc_gl_openglesdispatch, inc_glm, inc_host_common, - inc_common_logging, - inc_host_snapshot, inc_include, inc_opengl_headers, ], link_with: [ lib_common_base, - lib_host_common, lib_common_logging, + lib_host_common, ], ) diff --git a/host/gl/glestranslator/gles_v2/BUILD.bazel b/host/gl/glestranslator/gles_v2/BUILD.bazel index 16d96dc5a..640c820c6 100644 --- a/host/gl/glestranslator/gles_v2/BUILD.bazel +++ b/host/gl/glestranslator/gles_v2/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -30,6 +30,7 @@ cc_library( ], defines = GFXSTREAM_HOST_DEFINES, includes = ["."], + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ "//common/base:gfxstream_common_base", "//common/logging:gfxstream_common_logging", diff --git a/host/gl/glestranslator/gles_v2/meson.build b/host/gl/glestranslator/gles_v2/meson.build index 454d18b86..6292e02b7 100644 --- a/host/gl/glestranslator/gles_v2/meson.build +++ b/host/gl/glestranslator/gles_v2/meson.build @@ -19,22 +19,21 @@ lib_glesv2_translator = static_library( cpp_args: gfxstream_host_args, include_directories: [ inc_common_base, + inc_common_logging, inc_etc, inc_gfxstream_server, inc_gl_common, inc_gl_openglesdispatch, inc_host_common, inc_host_decoder_common, - inc_common_logging, - inc_host_snapshot, inc_include, inc_opengl_headers, inc_stream_servers, ], link_with: [ lib_common_base, + lib_common_logging, lib_host_common, lib_host_decoder_common, - lib_common_logging, ], ) diff --git a/host/gl/glsnapshot/BUILD.bazel b/host/gl/glsnapshot/BUILD.bazel index b42d7d820..bba9735ab 100644 --- a/host/gl/glsnapshot/BUILD.bazel +++ b/host/gl/glsnapshot/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -15,6 +15,7 @@ cc_library( ], defines = GFXSTREAM_HOST_DEFINES, includes = ["."], + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ "//host/decoder_common:gfxstream_host_decoder_common", "//host/gl/OpenGLESDispatch:gfxstream_host_openglesdispatch", diff --git a/host/gl/meson.build b/host/gl/meson.build index 84a2225c1..d3aad7c3b 100644 --- a/host/gl/meson.build +++ b/host/gl/meson.build @@ -29,6 +29,7 @@ files_lib_gl_server = files( 'emulation_gl.cpp', 'gles_version_detector.cpp', 'pixel_read_formats.cpp', + 'post_worker_gl.cpp', 'readback_worker_gl.cpp', 'render_thread_info_gl.cpp', 'texture_draw.cpp', @@ -56,7 +57,6 @@ lib_gl_server = static_library( inc_host_iostream, inc_host_library, inc_host_renderdoc, - inc_host_snapshot, inc_include, inc_opengl_headers, inc_renderdoc_external, diff --git a/host/post_worker_gl.cpp b/host/gl/post_worker_gl.cpp similarity index 88% rename from host/post_worker_gl.cpp rename to host/gl/post_worker_gl.cpp index 6d133350e..711bff5d2 100644 --- a/host/post_worker_gl.cpp +++ b/host/gl/post_worker_gl.cpp @@ -15,13 +15,13 @@ */ #include "post_worker_gl.h" -#include "frame_buffer.h" -#include "gfxstream/host/display_operations.h" +#include "display_gl.h" +#include "display_surface_gl.h" #include "gfxstream/common/logging.h" +#include "gfxstream/host/display_operations.h" +#include "gfxstream/host/global_state.h" #include "gfxstream/host/renderer_operations.h" #include "gfxstream/host/window_operations.h" -#include "host/gl/display_gl.h" -#include "host/gl/display_surface_gl.h" namespace gfxstream { namespace host { @@ -43,9 +43,10 @@ hwc_transform_t getTransformFromRotation(int rotation) { } // namespace -PostWorkerGl::PostWorkerGl(bool mainThreadPostingOnly, FrameBuffer* fb, Compositor* compositor, - DisplayGl* displayGl, gl::EmulationGl* emulationGl) - : PostWorker(mainThreadPostingOnly, fb, compositor), +PostWorkerGl::PostWorkerGl(bool mainThreadPostingOnly, gfxstream::host::GlobalState* globalState, + Compositor* compositor, DisplayGl* displayGl, + gl::EmulationGl* emulationGl) + : PostWorker(mainThreadPostingOnly, globalState, compositor), m_displayGl(displayGl), mEmulationGl(emulationGl) { if (!m_displayGl) { @@ -54,7 +55,7 @@ PostWorkerGl::PostWorkerGl(bool mainThreadPostingOnly, FrameBuffer* fb, Composit } std::shared_future PostWorkerGl::postImpl( - ColorBuffer* cb, const std::optional>& colorTransform) { + IColorBuffer* cb, const std::optional>& colorTransform) { if (!mContextBound || m_mainThreadPostingOnly) { // This might happen on headless mode // Also if posting on main thread, the context binding can get polluted easily, which @@ -130,17 +131,17 @@ std::shared_future PostWorkerGl::postImpl( continue; } - ColorBuffer* currentCb = + IColorBuffer* currentCb = currentDisplayId == 0 ? cb - : mFb->findColorBuffer(currentDisplayColorBufferHandle).get(); + : m_globalState->findColorBuffer(currentDisplayColorBufferHandle).get(); if (!currentCb) { continue; } - const auto transform = getTransformFromRotation(mFb->getZrot()); + const auto transform = getTransformFromRotation(m_globalState->getZrot()); postLayerOptions.transform = transform; - if ( transform == HWC_TRANSFORM_ROT_90 || transform == HWC_TRANSFORM_ROT_270) { + if (transform == HWC_TRANSFORM_ROT_90 || transform == HWC_TRANSFORM_ROT_270) { std::swap(currentDisplayW, currentDisplayH); } postLayerOptions.displayFrame = { @@ -163,7 +164,7 @@ std::shared_future PostWorkerGl::postImpl( } } } else if (get_gfxstream_window_operations().is_folded()) { - const float dpr = mFb->getDpr(); + const float dpr = m_globalState->getDpr(); post.frameWidth = m_viewportWidth / dpr; post.frameHeight = m_viewportHeight / dpr; @@ -179,8 +180,8 @@ std::shared_future PostWorkerGl::postImpl( postLayerOptions.displayFrame = { .left = 0, .top = 0, - .right = mFb->windowWidth(), - .bottom = mFb->windowHeight(), + .right = m_globalState->windowWidth(), + .bottom = m_globalState->windowHeight(), }; postLayerOptions.crop = { .left = static_cast(displayOffsetX), @@ -188,7 +189,7 @@ std::shared_future PostWorkerGl::postImpl( .right = static_cast(displayOffsetX + displayW), .bottom = static_cast(displayOffsetY), }; - postLayerOptions.transform = getTransformFromRotation(mFb->getZrot()); + postLayerOptions.transform = getTransformFromRotation(m_globalState->getZrot()); post.layers.push_back(DisplayGl::PostLayer{ .colorBuffer = cb, @@ -204,13 +205,13 @@ std::shared_future PostWorkerGl::postImpl( } DisplayGl::PostLayer PostWorkerGl::postWithOverlay( - ColorBuffer* cb, const std::optional>& colorTransform) { - float dpr = mFb->getDpr(); - int windowWidth = mFb->windowWidth(); - int windowHeight = mFb->windowHeight(); - float px = mFb->getPx(); - float py = mFb->getPy(); - int zRot = mFb->getZrot(); + IColorBuffer* cb, const std::optional>& colorTransform) { + float dpr = m_globalState->getDpr(); + int windowWidth = m_globalState->windowWidth(); + int windowHeight = m_globalState->windowHeight(); + float px = m_globalState->getPx(); + float py = m_globalState->getPy(); + int zRot = m_globalState->getZrot(); // Find the x and y values at the origin when "fully scrolled." // Multiply by 2 because the texture goes from -1 to 1, not 0 to 1. @@ -224,12 +225,7 @@ DisplayGl::PostLayer PostWorkerGl::postWithOverlay( float dy = py * fy; DisplayGl::PostLayer::OverlayOptions overlayOptions = { - .rotation = static_cast(zRot), - .dx = dx, - .dy = dy, - .scaleX = 1.0f, - .scaleY = 1.0f - }; + .rotation = static_cast(zRot), .dx = dx, .dy = dy, .scaleX = 1.0f, .scaleY = 1.0f}; // Adjust offset and scale parameters if a display layout is given Rect scaledDisplayRect = {}; @@ -256,7 +252,7 @@ DisplayGl::PostLayer PostWorkerGl::postWithOverlay( // and resets the posting viewport. void PostWorkerGl::viewportImpl(int width, int height) { setupContext(); - const float dpr = mFb->getDpr(); + const float dpr = m_globalState->getDpr(); m_viewportWidth = width * dpr; m_viewportHeight = height * dpr; diff --git a/host/post_worker_gl.h b/host/gl/post_worker_gl.h similarity index 80% rename from host/post_worker_gl.h rename to host/gl/post_worker_gl.h index 12f7db9f3..88b59a805 100644 --- a/host/post_worker_gl.h +++ b/host/gl/post_worker_gl.h @@ -18,10 +18,12 @@ #include #include +#include "display_gl.h" +#include "emulation_gl.h" +#include "gfxstream/host/color_buffer_interface.h" #include "gfxstream/host/display_surface_user.h" -#include "post_worker.h" -#include "host/gl/display_gl.h" -#include "host/gl/emulation_gl.h" +#include "gfxstream/host/global_state.h" +#include "gfxstream/host/post_worker.h" namespace gfxstream { namespace host { @@ -33,12 +35,12 @@ class RecursiveScopedContextBind; class PostWorkerGl : public PostWorker, public DisplaySurfaceUser { public: - PostWorkerGl(bool mainThreadPostingOnly, FrameBuffer* fb, Compositor* compositor, + PostWorkerGl(bool mainThreadPostingOnly, GlobalState* globalState, Compositor* compositor, gl::DisplayGl* displayGl, gl::EmulationGl* emulationGl); protected: std::shared_future postImpl( - ColorBuffer* cb, const std::optional>& colorTransform) override; + IColorBuffer* cb, const std::optional>& colorTransform) override; void viewportImpl(int width, int height) override; void clearImpl() override; void exitImpl() override; @@ -51,7 +53,7 @@ class PostWorkerGl : public PostWorker, public DisplaySurfaceUser { private: void setupContext(); gl::DisplayGl::PostLayer postWithOverlay( - ColorBuffer* cb, const std::optional>& colorTransform); + IColorBuffer* cb, const std::optional>& colorTransform); private: // TODO(b/233939967): conslidate DisplayGl and DisplayVk into diff --git a/host/gl/readback_worker_gl.cpp b/host/gl/readback_worker_gl.cpp index 073691f94..e771f4384 100644 --- a/host/gl/readback_worker_gl.cpp +++ b/host/gl/readback_worker_gl.cpp @@ -17,13 +17,13 @@ #include -#include "color_buffer.h" -#include "context_helper.h" #include "OpenGLESDispatch/DispatchTables.h" #include "OpenGLESDispatch/EGLDispatch.h" #include "OpenGLESDispatch/GLESv2Dispatch.h" +#include "color_buffer_gl.h" +#include "context_helper.h" #include "gfxstream/common/logging.h" -#include "gl/color_buffer_gl.h" +#include "gfxstream/host/color_buffer_interface.h" namespace gfxstream { namespace host { @@ -87,12 +87,10 @@ void ReadbackWorkerGl::deinitReadbackForDisplay(uint32_t displayId) { mTrackedDisplays.erase(it); } -ReadbackWorkerGl::DoNextReadbackResult -ReadbackWorkerGl::doNextReadback(uint32_t displayId, - ColorBuffer* cb, - void* fbImage, - bool repaint, - bool readbackBgra) { +ReadbackWorkerGl::DoNextReadbackResult ReadbackWorkerGl::doNextReadback(uint32_t displayId, + IColorBuffer* cb, + void* fbImage, bool repaint, + bool readbackBgra) { // if |repaint|, make sure that the current frame is immediately sent down // the pipeline and made available to the consumer by priming async // readback; doing 4 consecutive reads in a row, which should be enough to @@ -161,7 +159,11 @@ ReadbackWorkerGl::doNextReadback(uint32_t displayId, r.m_readbackCount++; r.mPrevReadPixelsIndex = readAt; - cb->glOpReadbackAsync(r.mBuffers[readAt], readbackBgra); + cb->touch(); + auto cbGl = cb->getColorBufferGl(); + if (cbGl) { + cbGl->readbackAsync(r.mBuffers[readAt], readbackBgra); + } // It's possible to post callback before any of the async readbacks // have written any data yet, which results in a black frame. Safer @@ -176,6 +178,23 @@ ReadbackWorkerGl::doNextReadback(uint32_t displayId, return ret; } +void ReadbackWorkerGl::doNextReadbackSync(IColorBuffer* colorBuffer, void* fbImage, + bool readbackBgra) { + if (!colorBuffer) { + return; + } + + ColorBufferGl* colorBufferGl = colorBuffer->getColorBufferGl(); + if (!colorBufferGl) { + GFXSTREAM_ERROR("Failed to get ColorBufferGl"); + return; + } + + colorBuffer->touch(); + + colorBufferGl->readback(static_cast(fbImage), readbackBgra); +} + ReadbackWorkerGl::FlushResult ReadbackWorkerGl::flushPipeline(uint32_t displayId) { gfxstream::base::AutoLock lock(mLock); diff --git a/host/gl/readback_worker_gl.h b/host/gl/readback_worker_gl.h index 0e8794711..13a4d0344 100644 --- a/host/gl/readback_worker_gl.h +++ b/host/gl/readback_worker_gl.h @@ -15,20 +15,22 @@ */ #pragma once -#include -#include -#include - #include #include +#include +#include +#include + +#include "display_surface_gl.h" #include "gfxstream/Compiler.h" +#include "gfxstream/host/readback_worker.h" #include "gfxstream/synchronization/Lock.h" -#include "display_surface_gl.h" -#include "readback_worker.h" namespace gfxstream { -class ColorBuffer; +namespace host { +class IColorBuffer; +} // namespace host } // namespace gfxstream namespace gfxstream { @@ -59,11 +61,10 @@ class ReadbackWorkerGl : public ReadbackWorker { // |readbackBgra|: Whether to force the readback format as GL_BGRA_EXT, // so that we get (depending on driver quality, heh) a gpu conversion of the // readback image that is suitable for webrtc, which expects formats like that. - DoNextReadbackResult doNextReadback(uint32_t displayId, - ColorBuffer* cb, - void* fbImage, - bool repaint, - bool readbackBgra) override; + DoNextReadbackResult doNextReadback(uint32_t displayId, IColorBuffer* cb, void* fbImage, + bool repaint, bool readbackBgra) override; + + void doNextReadbackSync(IColorBuffer* cb, void* fbImage, bool readbackBgra) override; // getPixels(): Run this on a separate GL thread. This retrieves the // latest framebuffer that has been posted and read with doNextReadback. diff --git a/host/gl/render_thread_info_gl.cpp b/host/gl/render_thread_info_gl.cpp index 7a2878b21..455e28129 100644 --- a/host/gl/render_thread_info_gl.cpp +++ b/host/gl/render_thread_info_gl.cpp @@ -16,13 +16,13 @@ #include -#include "frame_buffer.h" #include "OpenGLESDispatch/EGLDispatch.h" #include "OpenGLESDispatch/GLESv1Dispatch.h" #include "OpenGLESDispatch/GLESv2Dispatch.h" -#include "gfxstream/synchronization/Lock.h" +#include "emulation_gl.h" #include "gfxstream/containers/Lookup.h" #include "gfxstream/host/stream_utils.h" +#include "gfxstream/synchronization/Lock.h" namespace gfxstream { namespace host { @@ -34,7 +34,7 @@ using gfxstream::Stream; static thread_local RenderThreadInfoGl* tlThreadInfo = nullptr; -RenderThreadInfoGl::RenderThreadInfoGl() { +RenderThreadInfoGl::RenderThreadInfoGl(EmulationGl* emulationGl) : m_emulationGl(emulationGl) { m_glDec.initGL(gles1_dispatch_get_proc_func, nullptr); m_gl2Dec.initGL(gles2_dispatch_get_proc_func, nullptr); @@ -83,9 +83,8 @@ void RenderThreadInfoGl::onSave(Stream* stream) { stream->putBe64(0); } -bool RenderThreadInfoGl::onLoad(Stream* stream) { - FrameBuffer* fb = FrameBuffer::getFB(); - assert(fb); +bool RenderThreadInfoGl::onLoad(Stream* stream) NO_THREAD_SAFETY_ANALYSIS { + assert(m_emulationGl); HandleType ctxHndl = stream->getBe32(); HandleType drawSurf = stream->getBe32(); @@ -95,7 +94,9 @@ bool RenderThreadInfoGl::onLoad(Stream* stream) { currDrawSurfHandleFromLoad = drawSurf; currReadSurfHandleFromLoad = readSurf; - fb->postLoadRenderThreadContextSurfacePtrs(); + currContext = m_emulationGl->getContext(ctxHndl); + currDrawSurf = m_emulationGl->getWindowSurface(drawSurf); + currReadSurf = m_emulationGl->getWindowSurface(readSurf); loadCollection(stream, &m_contextSet, [](Stream* stream) { return stream->getBe32(); @@ -112,16 +113,17 @@ bool RenderThreadInfoGl::onLoad(Stream* stream) { return true; } -void RenderThreadInfoGl::postLoadRefreshCurrentContextSurfacePtrs() { - FrameBuffer* fb = FrameBuffer::getFB(); - assert(fb); +void RenderThreadInfoGl::postLoadRefreshCurrentContextSurfacePtrs() NO_THREAD_SAFETY_ANALYSIS { + assert(m_emulationGl); - fb->postLoadRenderThreadContextSurfacePtrs(); + currContext = m_emulationGl->getContext(currContextHandleFromLoad); + currDrawSurf = m_emulationGl->getWindowSurface(currDrawSurfHandleFromLoad); + currReadSurf = m_emulationGl->getWindowSurface(currReadSurfHandleFromLoad); const HandleType ctx = currContext ? currContext->getHndl() : 0; const HandleType draw = currDrawSurf ? currDrawSurf->getHndl() : 0; const HandleType read = currReadSurf ? currReadSurf->getHndl() : 0; - fb->bindContext(ctx, draw, read); + m_emulationGl->bindContext(ctx, draw, read); } } // namespace gl diff --git a/host/gl/render_thread_info_gl.h b/host/gl/render_thread_info_gl.h index 7fa866f3e..8acedddbb 100644 --- a/host/gl/render_thread_info_gl.h +++ b/host/gl/render_thread_info_gl.h @@ -17,23 +17,25 @@ #include #include -#include "handle.h" -#include "stale_ptr_registry.h" +#include "emulated_egl_context.h" +#include "emulated_egl_window_surface.h" +#include "gfxstream/host/handle.h" +#include "gles1_dec/gles_v1_decoder.h" +#include "gles2_dec/gles_v2_decoder.h" #include "render-utils/stream.h" -#include "gl/emulated_egl_context.h" -#include "gl/emulated_egl_window_surface.h" -#include "gl/gles1_dec/gles_v1_decoder.h" -#include "gl/gles2_dec/gles_v2_decoder.h" +#include "stale_ptr_registry.h" namespace gfxstream { namespace host { +class GlobalState; namespace gl { +class EmulationGl; struct RenderThreadInfoGl { // Create new instance. Only call this once per thread. // Future calls to get() will return this instance until // it is destroyed. - RenderThreadInfoGl(); + RenderThreadInfoGl(EmulationGl* emulationGl); // Destructor. ~RenderThreadInfoGl(); @@ -73,6 +75,8 @@ struct RenderThreadInfoGl { // Decoder states. GLESv1Decoder m_glDec; GLESv2Decoder m_gl2Dec; + + EmulationGl* m_emulationGl = nullptr; }; } // namespace gl diff --git a/host/stale_ptr_registry.h b/host/gl/stale_ptr_registry.h similarity index 100% rename from host/stale_ptr_registry.h rename to host/gl/stale_ptr_registry.h diff --git a/host/gl/texture_draw.h b/host/gl/texture_draw.h index 88e2f8f33..0be18a7f6 100644 --- a/host/gl/texture_draw.h +++ b/host/gl/texture_draw.h @@ -23,7 +23,7 @@ #include #include -#include "hwc2.h" +#include "gfxstream/host/hwc2.h" #include "gfxstream/synchronization/Lock.h" namespace gfxstream { diff --git a/host/gles_compat.h b/host/gles_compat.h deleted file mode 100644 index 6aef3b1ef..000000000 --- a/host/gles_compat.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2024 The Android Open Source Project -// -// 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. - -#ifndef GLES_COMPAT_H -#define GLES_COMPAT_H - -#include - -typedef unsigned int GLenum; -typedef int32_t EGLint; -// Must stay ABI-compatible with the real EGLNativeWindowType from -// , which is pointer-sized on 64-bit platforms -// (e.g. `void*` on Apple); a 32-bit integer here truncates pointers. -typedef void* EGLNativeWindowType; - -namespace gfxstream { -namespace gl { -class EmulationGl { - public: - EmulationGl() {} - ~EmulationGl() {} - - private: - uint32_t payload; -}; -} // namespace gl -} // namespace gfxstream - -#endif diff --git a/host/include/gfxstream/virtio-gpu-gfxstream-renderer.h b/host/include/gfxstream/virtio-gpu-gfxstream-renderer.h index afb20f532..83580c411 100644 --- a/host/include/gfxstream/virtio-gpu-gfxstream-renderer.h +++ b/host/include/gfxstream/virtio-gpu-gfxstream-renderer.h @@ -118,6 +118,20 @@ typedef void (*stream_renderer_fence_callback)(void* user_data, typedef void (*stream_renderer_debug_callback)(void* user_data, struct stream_renderer_debug* debug); +/** + * Extended debug data with location information. + */ +struct stream_renderer_debug_ex { + uint32_t debug_type; /**< The type of the debug message. */ + const char* file; /**< The source file where the log was generated. */ + int line; /**< The line number in the source file. */ + const char* function; /**< The function name where the log was generated. */ + const char* message; /**< The actual log message. */ +}; + +typedef void (*stream_renderer_debug_callback_ex)(void* user_data, + struct stream_renderer_debug_ex* debug); + // Parameters - data passed to initialize the renderer, with the goal of avoiding FFI breakages. // To change the data a parameter is passing safely, you should create a new parameter and // deprecate the old one. The old parameter may be removed after sufficient time. @@ -139,6 +153,7 @@ typedef void (*stream_renderer_debug_callback)(void* user_data, #define STREAM_RENDERER_PARAM_WIN0_WIDTH 4 #define STREAM_RENDERER_PARAM_WIN0_HEIGHT 5 #define STREAM_RENDERER_PARAM_DEBUG_CALLBACK 6 +#define STREAM_RENDERER_PARAM_DEBUG_CALLBACK_EX 7 // An entry in the stream renderer parameters list. // The key should be one of STREAM_RENDERER_PARAM_* diff --git a/host/include/render-utils/Renderer.h b/host/include/render-utils/Renderer.h index f38e840c5..0a1cf4bf6 100644 --- a/host/include/render-utils/Renderer.h +++ b/host/include/render-utils/Renderer.h @@ -297,7 +297,7 @@ class Renderer { // Resumes all channels after snapshot saving or loading. virtual void resumeAll() = 0; - virtual void save( + virtual bool save( Stream* stream, const ITextureSaverPtr& textureSaver) = 0; virtual bool load( diff --git a/host/iostream/BUILD.bazel b/host/iostream/BUILD.bazel index 70a35e883..0da6533e2 100644 --- a/host/iostream/BUILD.bazel +++ b/host/iostream/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -12,6 +12,7 @@ cc_library( copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, includes = ["include"], + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ "//common/logging:gfxstream_common_logging", "//host:gfxstream_backend_headers", diff --git a/host/library/BUILD.bazel b/host/library/BUILD.bazel index 5b2b26117..fd464e155 100644 --- a/host/library/BUILD.bazel +++ b/host/library/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -13,6 +13,7 @@ cc_library( copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, includes = ["include"], + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ "//common/base:gfxstream_common_base", "//common/logging:gfxstream_common_logging", diff --git a/host/meson.build b/host/meson.build index 3937c075f..1e8875a3f 100644 --- a/host/meson.build +++ b/host/meson.build @@ -16,26 +16,26 @@ subdir('iostream') subdir('library') subdir('tracing') subdir('renderdoc') -subdir('snapshot') subdir('decoder_common') subdir('address_space') subdir('common') +subdir('native_window') inc_gfxstream_backend = [ - inc_host_decoder_common, inc_common_base, + inc_common_logging, inc_common_utils, inc_drm_headers, inc_glm, inc_host_address_space, inc_host_common, + inc_host_decoder_common, inc_host_features, inc_host_include, inc_host_iostream, inc_host_library, - inc_common_logging, + inc_host_native_window, inc_host_renderdoc, - inc_host_snapshot, inc_host_tracing, inc_include, inc_opengl_headers, @@ -43,14 +43,15 @@ inc_gfxstream_backend = [ ] link_gfxstream_backend = [ - lib_host_decoder_common, lib_common_base, + lib_common_logging, lib_common_utils, lib_host_address_space, lib_host_common, + lib_host_decoder_common, lib_host_features, lib_host_library, - lib_common_logging, + lib_host_native_window, lib_host_tracing, ] @@ -59,8 +60,6 @@ files_lib_gfxstream_backend = files( 'channel_stream.cpp', 'color_buffer.cpp', 'frame_buffer.cpp', - 'hwc2.cpp', - 'post_worker.cpp', 'read_buffer.cpp', 'render_api.cpp', 'render_channel_impl.cpp', @@ -102,7 +101,6 @@ inc_gl_openglesdispatch = include_directories('gl/OpenGLESDispatch/include') if use_gles subdir('gl') - files_lib_gfxstream_backend += files('post_worker_gl.cpp') files_lib_gfxstream_backend += files('render_control.cpp') inc_gfxstream_backend += [ @@ -129,21 +127,6 @@ if use_composer link_gfxstream_backend += lib_composer endif -if not use_gles - files_lib_gfxstream_backend += files('native_sub_window_stub.cpp') -elif host_machine.system() == 'darwin' - files_lib_gfxstream_backend += files('native_sub_window_cocoa.mm') -elif host_machine.system() == 'windows' - files_lib_gfxstream_backend += files('native_sub_window_win32.cpp') -elif host_machine.system() == 'linux' and use_gles - files_lib_gfxstream_backend += files('native_sub_window_x11.cpp') -elif host_machine.system() == 'qnx' - files_lib_gfxstream_backend += files( - 'platform_helper_qnx.cpp', - 'native_sub_window_qnx.cpp', - ) -endif - gfxstream_backend_cpp_args = [ '-Wno-unused-parameter', '-Wno-unused-variable', diff --git a/host/native_sub_window_android.cpp b/host/native_sub_window_android.cpp deleted file mode 100644 index 93edad0a4..000000000 --- a/host/native_sub_window_android.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* -* Copyright (C) 2011 The Android Open Source Project -* -* 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 "native_sub_window.h" - -#include - -#include - -EGLNativeWindowType createSubWindow(FBNativeWindowType p_window, - int x, - int y, - int width, - int height, - float dpr, - SubWindowRepaintCallback repaint_callback, - void* repaint_callback_param, - int hideWindow) { - ANativeWindow_acquire(p_window); - ANativeWindow_setBuffersGeometry(p_window, width, height, AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM); - return p_window; -} - -void destroySubWindow(EGLNativeWindowType win) { - ANativeWindow_release(win); -} - -int moveSubWindow(FBNativeWindowType p_parent_window, - EGLNativeWindowType p_sub_window, - int x, - int y, - int width, - int height, - float dpr) { - // moving windows not supported in Android; we can't create an actual sub window - return true; -} - -void* getNativeDisplay() { - fprintf(stderr, "%s: Unimplemented\n", __func__); - return nullptr; -} diff --git a/host/native_sub_window_win32.cpp b/host/native_sub_window_win32.cpp deleted file mode 100644 index 4ba8fc154..000000000 --- a/host/native_sub_window_win32.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/* -* Copyright (C) 2011 The Android Open Source Project -* -* 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 "native_sub_window.h" - -#include - -struct SubWindowUserData { - SubWindowRepaintCallback repaint_callback; - void* repaint_callback_param; -}; - -static LRESULT CALLBACK subWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { - if (uMsg == WM_PAINT) { - auto user_data = - (SubWindowUserData*)GetWindowLongPtr(hwnd, GWLP_USERDATA); - if (user_data && user_data->repaint_callback) { - user_data->repaint_callback(user_data->repaint_callback_param); - } - } else if (uMsg == WM_NCDESTROY) { - SubWindowUserData* user_data = - (SubWindowUserData*)GetWindowLongPtr(hwnd, GWLP_USERDATA); - delete user_data; - } - return DefWindowProcA(hwnd, uMsg, wParam, lParam); -} - -EGLNativeWindowType createSubWindow(FBNativeWindowType p_window, - int x, int y,int width, int height, float dpr, - SubWindowRepaintCallback repaint_callback, - void* repaint_callback_param, int hideWindow){ - static const char className[] = "subWin"; - - WNDCLASSA wc = {}; - if (!GetClassInfoA(GetModuleHandle(NULL), className, &wc)) { - wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;// redraw if size changes - wc.lpfnWndProc = &subWindowProc; // points to window procedure - wc.cbWndExtra = sizeof(void*) ; // save extra window memory - wc.lpszClassName = className; // name of window class - RegisterClassA(&wc); - } - - // We assume size/pos are passed in as logical size/coordinates. Convert it to pixel - // coordinates. - x *= dpr; - y *= dpr; - width *= dpr; - height *= dpr; - EGLNativeWindowType ret = CreateWindowExA( - WS_EX_NOPARENTNOTIFY, // do not bother our parent window - className, - "sub", - WS_CHILD|WS_DISABLED, - x,y,width,height, - p_window, - NULL, - NULL, - NULL); - - auto user_data = new SubWindowUserData(); - user_data->repaint_callback = repaint_callback; - user_data->repaint_callback_param = repaint_callback_param; - - SetWindowLongPtr(ret, GWLP_USERDATA, (LONG_PTR)user_data); - if (!hideWindow) - ShowWindow(ret, SW_SHOW); - return ret; -} - -void destroySubWindow(EGLNativeWindowType win){ - PostMessage(win, WM_CLOSE, 0, 0); -} - -int moveSubWindow(FBNativeWindowType p_parent_window, - EGLNativeWindowType p_sub_window, - int x, - int y, - int width, - int height, - float dpr) { - BOOL ret = MoveWindow(p_sub_window, - x * dpr, - y * dpr, - width * dpr, - height * dpr, - TRUE); - return ret; -} - -void* getNativeDisplay() { - fprintf(stderr, "%s: Unimplemented\n", __func__); - return nullptr; -} diff --git a/host/native_sub_window_x11.cpp b/host/native_sub_window_x11.cpp deleted file mode 100644 index 062ace8ec..000000000 --- a/host/native_sub_window_x11.cpp +++ /dev/null @@ -1,141 +0,0 @@ -/* -* Copyright (C) 2011 The Android Open Source Project -* -* 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 "native_sub_window.h" - -#include - -#include "gfxstream/host/X11Support.h" - -namespace { - -static Bool WaitForMapNotify(Display *d, XEvent *e, char *arg) { - if (e->type == MapNotify && e->xmap.window == (Window)arg) { - return 1; - } - return 0; -} - -static Bool WaitForConfigureNotify(Display *d, XEvent *e, char *arg) { - if (e->type == ConfigureNotify && e->xmap.window == (Window)arg) { - return 1; - } - return 0; -} - -static Display *s_display = NULL; - -} // namespace - -EGLNativeWindowType createSubWindow(FBNativeWindowType p_window, - int x, - int y, - int width, - int height, - float dpr, - SubWindowRepaintCallback repaint_callback, - void* repaint_callback_param, - int hideWindow) { - auto x11 = getX11Api(); - // The call to this function is protected by a lock - // in FrameBuffer so it is safe to check and initialize s_display here - if (!s_display) { - s_display = x11->XOpenDisplay(NULL); - } - - XSetWindowAttributes wa; - wa.event_mask = StructureNotifyMask; - wa.override_redirect = True; - Window win = x11->XCreateWindow(s_display, - p_window, - x * dpr, - y * dpr, - width * dpr, - height * dpr, - 0, - CopyFromParent, - CopyFromParent, - CopyFromParent, - CWEventMask, - &wa); - if (!hideWindow) { - x11->XMapWindow(s_display,win); - x11->XSetWindowBackground(s_display, win, 0); - XEvent e; - x11->XIfEvent(s_display, &e, WaitForMapNotify, (char *)win); - } - return win; -} - -void destroySubWindow(EGLNativeWindowType win) { - if (!s_display) { - return; - } - - getX11Api()->XDestroyWindow(s_display, win); -} - -int moveSubWindow(FBNativeWindowType p_parent_window, - EGLNativeWindowType p_sub_window, - int x, - int y, - int width, - int height, - float dpr) { - // This value is set during create, so if it is still null, simply - // return because the global state is corrupted - if (!s_display) { - return false; - } - - x *= dpr; - y *= dpr; - width *= dpr; - height *= dpr; - - auto x11 = getX11Api(); - - // Make sure something has changed, otherwise XIfEvent will block and - // freeze the emulator. - XWindowAttributes attrs; - if (!x11->XGetWindowAttributes(s_display, p_sub_window, &attrs)) { - return false; - } - if (x == attrs.x && y == attrs.y && - width == attrs.width && height == attrs.height) { - // Technically, resizing was a success because it was unneeded. - return true; - } - - // This prevents flicker on resize. - x11->XSetWindowBackgroundPixmap(s_display, p_sub_window, None); - - int ret = x11->XMoveResizeWindow( - s_display, - p_sub_window, - x, - y, - width, - height); - - XEvent e; - x11->XIfEvent(s_display, &e, WaitForConfigureNotify, (char *)p_sub_window); - - return ret; -} - -void* getNativeDisplay() { - return s_display; -} diff --git a/host/native_window/Android.bp b/host/native_window/Android.bp new file mode 100644 index 000000000..02e463fd6 --- /dev/null +++ b/host/native_window/Android.bp @@ -0,0 +1,36 @@ +package { + default_applicable_licenses: ["hardware_google_gfxstream_license"], +} + +cc_library_static { + name: "libgfxstream_host_native_window", + defaults: ["gfxstream_host_cc_defaults"], + srcs: [ + "native_sub_window_stub.cpp", + ], + target: { + host: { + srcs: ["native_sub_window_x11.cpp"], + static_libs: [ + "libgfxstream_host_decoder_common", + ], + }, + android: { + srcs: ["native_sub_window_android.cpp"], + shared_libs: [ + "libnativewindow", + ], + }, + darwin: { + srcs: ["native_sub_window_cocoa.mm"], + }, + windows: { + srcs: ["native_sub_window_win32.cpp"], + }, + }, + export_include_dirs: ["include"], + header_libs: [ + "libgfxstream_backend_headers", + "libgfxstream_thirdparty_opengl_headers", + ], +} diff --git a/host/native_window/BUILD.bazel b/host/native_window/BUILD.bazel new file mode 100644 index 000000000..62a08f204 --- /dev/null +++ b/host/native_window/BUILD.bazel @@ -0,0 +1,74 @@ +load("@rules_cc//cc:defs.bzl", "cc_library", "objc_library") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") + +package( + default_applicable_licenses = ["//:gfxstream_license"], + default_visibility = ["//:gfxstream"], +) + +objc_library( + name = "gfxstream_host_native_window-darwin", + srcs = [ + "native_sub_window_cocoa.mm", + ], + hdrs = [ + "include/gfxstream/host/native_sub_window.h", + ], + copts = GFXSTREAM_HOST_COPTS + [ + "-Wno-deprecated-declarations", + "-std=c++20", + "-fno-objc-arc", + ], + defines = GFXSTREAM_HOST_DEFINES, + includes = ["include"], + sdk_frameworks = [ + "AppKit", + "QuartzCore", + "IOSurface", + ], + target_compatible_with = [ + "@platforms//os:macos", + ], + deps = [ + "//host:gfxstream_backend_headers", + "//third_party/opengl:gfxstream_egl_headers", + ], +) + +cc_library( + name = "gfxstream_host_native_window", + srcs = select({ + "@platforms//os:macos": [], + "@platforms//os:windows": [ + "native_sub_window_win32.cpp", + ], + "@platforms//os:linux": [ + "native_sub_window_x11.cpp", + ], + "//conditions:default": [ + "native_sub_window_stub.cpp", + ], + }), + hdrs = [ + "include/gfxstream/host/native_sub_window.h", + ], + copts = GFXSTREAM_HOST_COPTS, + defines = GFXSTREAM_HOST_DEFINES, + includes = ["include"], + linkopts = GFXSTREAM_HOST_LINKOPTS, + deps = select({ + "@platforms//os:macos": [ + ":gfxstream_host_native_window-darwin", + ], + "//conditions:default": [], + }) + [ + "//common/base:gfxstream_common_base", + "//common/logging:gfxstream_common_logging", + "//host:gfxstream_backend_headers", + "//host/decoder_common:gfxstream_host_decoder_common", + "//third_party/opengl:gfxstream_egl_headers", + "//third_party/opengl:gfxstream_gles2_headers", + "//third_party/opengl:gfxstream_gles3_headers", + "//third_party/xcb", + ], +) diff --git a/host/native_window/CMakeLists.txt b/host/native_window/CMakeLists.txt new file mode 100644 index 000000000..c31cab603 --- /dev/null +++ b/host/native_window/CMakeLists.txt @@ -0,0 +1,35 @@ + + +if (APPLE) + set(gfxstream_host_native_window_platform_sources + native_sub_window_cocoa.mm) +elseif (WIN32) + set(gfxstream_host_native_window_platform_sources + native_sub_window_win32.cpp) +elseif (QNX) + set(gfxstream_host_native_window_platform_sources + native_sub_window_qnx.cpp) +else() + set(gfxstream_host_native_window_platform_sources + native_sub_window_x11.cpp) +endif() + + +add_library( + gfxstream_host_native_window + STATIC + ${gfxstream_host_native_window_platform_sources}) + +target_include_directories( + gfxstream_host_native_window + PUBLIC + include + ) + +target_link_libraries( + gfxstream_host_native_window + PRIVATE + gfxstream_common_base + gfxstream_backend_headers + gfxstream_host_decoder_common + ) diff --git a/host/native_sub_window.h b/host/native_window/include/gfxstream/host/native_sub_window.h similarity index 62% rename from host/native_sub_window.h rename to host/native_window/include/gfxstream/host/native_sub_window.h index 3791a9e71..d7e4a37f9 100644 --- a/host/native_sub_window.h +++ b/host/native_window/include/gfxstream/host/native_sub_window.h @@ -1,27 +1,34 @@ /* -* Copyright (C) 2011 The Android Open Source Project -* -* 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. -*/ + * Copyright (C) 2011 The Android Open Source Project + * + * 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. + */ #ifndef NATIVE_SUB_WINDOW_H #define NATIVE_SUB_WINDOW_H +#include + #include "render-utils/render_api_platform_types.h" #if GFXSTREAM_ENABLE_HOST_GLES #include #else -#include "gles_compat.h" +typedef unsigned int GLenum; +typedef int32_t EGLint; +// Must stay ABI-compatible with the real EGLNativeWindowType from +// , which is pointer-sized on 64-bit platforms +// (e.g. `void*` on Apple); a 32-bit integer here truncates pointers. +typedef void* EGLNativeWindowType; #endif #ifdef __cplusplus @@ -44,15 +51,10 @@ typedef void (*SubWindowRepaintCallback)(void*); // repaint callback when/if it's invoked. // On success, return a new platform-specific window handle, cast as an // EGLNativeWindowType. Or 0/NULL in case of failure. -EGLNativeWindowType createSubWindow(FBNativeWindowType p_window, - int x, - int y, - int width, - int height, - float dpr, +EGLNativeWindowType createSubWindow(FBNativeWindowType p_window, int x, int y, int width, + int height, float dpr, SubWindowRepaintCallback repaint_callback, - void* repaint_callback_param, - int hideWindow); + void* repaint_callback_param, int hideWindow); // Destroy a sub-window previously created through createSubWindow() above. void destroySubWindow(EGLNativeWindowType win); @@ -62,13 +64,8 @@ void destroySubWindow(EGLNativeWindowType win); // |p_sub_window| is the platform-specific handle to the EGL subwindow. // |x|,|y|,|width|,|height| are the new location and dimensions of the // subwindow. -int moveSubWindow(FBNativeWindowType p_parent_window, - EGLNativeWindowType p_sub_window, - int x, - int y, - int width, - int height, - float dpr); +int moveSubWindow(FBNativeWindowType p_parent_window, EGLNativeWindowType p_sub_window, int x, + int y, int width, int height, float dpr); void* getNativeDisplay(); diff --git a/host/native_window/meson.build b/host/native_window/meson.build new file mode 100644 index 000000000..fe6a556c7 --- /dev/null +++ b/host/native_window/meson.build @@ -0,0 +1,40 @@ +# Copyright 2026 Android Open Source Project +# SPDX-License-Identifier: Apache-2.0 + +inc_host_native_window = include_directories('include') + +files_lib_host_native_window = files() + +includes_lib_host_native_window = [ + inc_common_base, + inc_host_common, + inc_host_decoder_common, + inc_host_include, + inc_host_native_window, + inc_opengl_headers, +] + +if not use_gles + files_lib_host_native_window += files('native_sub_window_stub.cpp') +elif host_machine.system() == 'darwin' + files_lib_host_native_window += files('native_sub_window_cocoa.mm') + includes_lib_host_native_window += [inc_opengl_headers] +elif host_machine.system() == 'windows' + files_lib_host_native_window += files('native_sub_window_win32.cpp') + includes_lib_host_native_window += [inc_opengl_headers] +elif host_machine.system() == 'linux' and use_gles + files_lib_host_native_window += files('native_sub_window_x11.cpp') + includes_lib_host_native_window += [inc_opengl_headers] +elif host_machine.system() == 'qnx' + files_lib_host_native_window += files( + 'native_sub_window_qnx.cpp', + ) +endif + +lib_host_native_window = static_library( + 'host_native_window', + files_lib_host_native_window, + include_directories: includes_lib_host_native_window, + cpp_args: gfxstream_host_args, + objcpp_args: gfxstream_host_args, +) diff --git a/host/native_window/native_sub_window_android.cpp b/host/native_window/native_sub_window_android.cpp new file mode 100644 index 000000000..cafb1fe8d --- /dev/null +++ b/host/native_window/native_sub_window_android.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * 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 +#include + +#include "gfxstream/host/native_sub_window.h" + +EGLNativeWindowType createSubWindow(FBNativeWindowType p_window, int x, int y, int width, + int height, float dpr, + SubWindowRepaintCallback repaint_callback, + void* repaint_callback_param, int hideWindow) { + ANativeWindow_acquire(p_window); + ANativeWindow_setBuffersGeometry(p_window, width, height, + AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM); + return p_window; +} + +void destroySubWindow(EGLNativeWindowType win) { ANativeWindow_release(win); } + +int moveSubWindow(FBNativeWindowType p_parent_window, EGLNativeWindowType p_sub_window, int x, + int y, int width, int height, float dpr) { + // moving windows not supported in Android; we can't create an actual sub window + return true; +} + +void* getNativeDisplay() { + fprintf(stderr, "%s: Unimplemented\n", __func__); + return nullptr; +} diff --git a/host/native_sub_window_cocoa.mm b/host/native_window/native_sub_window_cocoa.mm similarity index 66% rename from host/native_sub_window_cocoa.mm rename to host/native_window/native_sub_window_cocoa.mm index 49790f079..583d060c5 100644 --- a/host/native_sub_window_cocoa.mm +++ b/host/native_window/native_sub_window_cocoa.mm @@ -1,24 +1,23 @@ /* -* Copyright (C) 2011 The Android Open Source Project -* -* 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. -*/ + * Copyright (C) 2011 The Android Open Source Project + * + * 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. + */ #import #import - -#include "native_sub_window.h" #include +#include "gfxstream/host/native_sub_window.h" /* * EmuGLView inherit from NSOpenGLView and override the isOpaque @@ -26,51 +25,46 @@ * when the view needs to be redrawn. */ @interface EmuGLView : NSOpenGLView { -} @end +} +@end @implementation EmuGLView - - (BOOL)isOpaque { - return YES; - } +- (BOOL)isOpaque { + return YES; +} @end @interface EmuGLViewWithMetal : NSOpenGLView -- (CAMetalLayer *)getMetalLayer; +- (CAMetalLayer*)getMetalLayer; @end - @implementation EmuGLViewWithMetal - - (BOOL)isOpaque { - return YES; - } +- (BOOL)isOpaque { + return YES; +} - - (CALayer *)makeBackingLayer { - CALayer * layer = [CAMetalLayer layer]; +- (CALayer*)makeBackingLayer { + CALayer* layer = [CAMetalLayer layer]; return layer; - } +} - - (CAMetalLayer *)getMetalLayer { - // The 'layer' property on NSView returns a CALayer. We can safely cast it - // to CAMetalLayer because we configured the view to use it. - return (CAMetalLayer *)self.layer; - } +- (CAMetalLayer*)getMetalLayer { + // The 'layer' property on NSView returns a CALayer. We can safely cast it + // to CAMetalLayer because we configured the view to use it. + return (CAMetalLayer*)self.layer; +} @end -EGLNativeWindowType createSubWindow(FBNativeWindowType p_window, - int x, - int y, - int width, - int height, - float dpr, +EGLNativeWindowType createSubWindow(FBNativeWindowType p_window, int x, int y, int width, + int height, float dpr, SubWindowRepaintCallback repaint_callback, - void* repaint_callback_param, - int hideWindow) { - NSWindow* win = (NSWindow *)p_window; + void* repaint_callback_param, int hideWindow) { + NSWindow* win = (NSWindow*)p_window; if (!win) { return NULL; } @@ -116,26 +110,21 @@ EGLNativeWindowType createSubWindow(FBNativeWindowType p_window, } void destroySubWindow(EGLNativeWindowType win) { - if(win){ - NSView *glView = (NSView *)win; + if (win) { + NSView* glView = (NSView*)win; [glView removeFromSuperview]; [glView release]; } } -int moveSubWindow(FBNativeWindowType p_parent_window, - EGLNativeWindowType p_sub_window, - int x, - int y, - int width, - int height, - float dpr) { - NSWindow *win = (NSWindow *)p_parent_window; +int moveSubWindow(FBNativeWindowType p_parent_window, EGLNativeWindowType p_sub_window, int x, + int y, int width, int height, float dpr) { + NSWindow* win = (NSWindow*)p_parent_window; if (!win) { return 0; } - NSView *glView = (NSView *)p_sub_window; + NSView* glView = (NSView*)p_sub_window; if (!glView) { return 0; } diff --git a/host/native_sub_window_qnx.cpp b/host/native_window/native_sub_window_qnx.cpp similarity index 98% rename from host/native_sub_window_qnx.cpp rename to host/native_window/native_sub_window_qnx.cpp index cf459e0d3..21b9cdbed 100644 --- a/host/native_sub_window_qnx.cpp +++ b/host/native_window/native_sub_window_qnx.cpp @@ -17,7 +17,7 @@ #include -#include "native_sub_window.h" +#include "gfxstream/host/native_sub_window.h" #include "platform_helper_qnx.h" EGLNativeWindowType createSubWindow(FBNativeWindowType p_window, int x, int y, int width, diff --git a/host/native_sub_window_stub.cpp b/host/native_window/native_sub_window_stub.cpp similarity index 95% rename from host/native_sub_window_stub.cpp rename to host/native_window/native_sub_window_stub.cpp index c4379bc19..6375fdd65 100644 --- a/host/native_sub_window_stub.cpp +++ b/host/native_window/native_sub_window_stub.cpp @@ -14,8 +14,9 @@ * limitations under the License. */ -#include "gles_compat.h" -#include "native_sub_window.h" +#include + +#include "gfxstream/host/native_sub_window.h" EGLNativeWindowType createSubWindow(FBNativeWindowType p_window, int x, int y, int width, int height, float dpr, diff --git a/host/native_window/native_sub_window_win32.cpp b/host/native_window/native_sub_window_win32.cpp new file mode 100644 index 000000000..7f9806958 --- /dev/null +++ b/host/native_window/native_sub_window_win32.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * 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 + +#include "gfxstream/host/native_sub_window.h" + +struct SubWindowUserData { + SubWindowRepaintCallback repaint_callback; + void* repaint_callback_param; +}; + +static LRESULT CALLBACK subWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { + if (uMsg == WM_PAINT) { + auto user_data = (SubWindowUserData*)GetWindowLongPtr(hwnd, GWLP_USERDATA); + if (user_data && user_data->repaint_callback) { + user_data->repaint_callback(user_data->repaint_callback_param); + } + } else if (uMsg == WM_NCDESTROY) { + SubWindowUserData* user_data = (SubWindowUserData*)GetWindowLongPtr(hwnd, GWLP_USERDATA); + delete user_data; + } + return DefWindowProcA(hwnd, uMsg, wParam, lParam); +} + +EGLNativeWindowType createSubWindow(FBNativeWindowType p_window, int x, int y, int width, + int height, float dpr, + SubWindowRepaintCallback repaint_callback, + void* repaint_callback_param, int hideWindow) { + static const char className[] = "subWin"; + + WNDCLASSA wc = {}; + if (!GetClassInfoA(GetModuleHandle(NULL), className, &wc)) { + wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; // redraw if size changes + wc.lpfnWndProc = &subWindowProc; // points to window procedure + wc.cbWndExtra = sizeof(void*); // save extra window memory + wc.lpszClassName = className; // name of window class + RegisterClassA(&wc); + } + + // We assume size/pos are passed in as logical size/coordinates. Convert it to pixel + // coordinates. + x *= dpr; + y *= dpr; + width *= dpr; + height *= dpr; + EGLNativeWindowType ret = CreateWindowExA( + WS_EX_NOPARENTNOTIFY, // do not bother our parent window + className, "sub", WS_CHILD | WS_DISABLED, x, y, width, height, p_window, NULL, NULL, NULL); + + auto user_data = new SubWindowUserData(); + user_data->repaint_callback = repaint_callback; + user_data->repaint_callback_param = repaint_callback_param; + + SetWindowLongPtr(ret, GWLP_USERDATA, (LONG_PTR)user_data); + if (!hideWindow) ShowWindow(ret, SW_SHOW); + return ret; +} + +void destroySubWindow(EGLNativeWindowType win) { PostMessage(win, WM_CLOSE, 0, 0); } + +int moveSubWindow(FBNativeWindowType p_parent_window, EGLNativeWindowType p_sub_window, int x, + int y, int width, int height, float dpr) { + BOOL ret = MoveWindow(p_sub_window, x * dpr, y * dpr, width * dpr, height * dpr, TRUE); + return ret; +} + +void* getNativeDisplay() { + fprintf(stderr, "%s: Unimplemented\n", __func__); + return nullptr; +} diff --git a/host/native_window/native_sub_window_x11.cpp b/host/native_window/native_sub_window_x11.cpp new file mode 100644 index 000000000..6f917661e --- /dev/null +++ b/host/native_window/native_sub_window_x11.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * 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 + +#include "gfxstream/host/X11Support.h" +#include "gfxstream/host/native_sub_window.h" + +namespace { + +static Bool WaitForMapNotify(Display* d, XEvent* e, char* arg) { + if (e->type == MapNotify && e->xmap.window == (Window)arg) { + return 1; + } + return 0; +} + +static Bool WaitForConfigureNotify(Display* d, XEvent* e, char* arg) { + if (e->type == ConfigureNotify && e->xmap.window == (Window)arg) { + return 1; + } + return 0; +} + +static Display* s_display = NULL; + +} // namespace + +EGLNativeWindowType createSubWindow(FBNativeWindowType p_window, int x, int y, int width, + int height, float dpr, + SubWindowRepaintCallback repaint_callback, + void* repaint_callback_param, int hideWindow) { + auto x11 = getX11Api(); + // The call to this function is protected by a lock + // in FrameBuffer so it is safe to check and initialize s_display here + if (!s_display) { + s_display = x11->XOpenDisplay(NULL); + } + + XSetWindowAttributes wa; + wa.event_mask = StructureNotifyMask; + wa.override_redirect = True; + Window win = + x11->XCreateWindow(s_display, p_window, x * dpr, y * dpr, width * dpr, height * dpr, 0, + CopyFromParent, CopyFromParent, CopyFromParent, CWEventMask, &wa); + if (!hideWindow) { + x11->XMapWindow(s_display, win); + x11->XSetWindowBackground(s_display, win, 0); + XEvent e; + x11->XIfEvent(s_display, &e, WaitForMapNotify, (char*)win); + } + return win; +} + +void destroySubWindow(EGLNativeWindowType win) { + if (!s_display) { + return; + } + + getX11Api()->XDestroyWindow(s_display, win); +} + +int moveSubWindow(FBNativeWindowType p_parent_window, EGLNativeWindowType p_sub_window, int x, + int y, int width, int height, float dpr) { + // This value is set during create, so if it is still null, simply + // return because the global state is corrupted + if (!s_display) { + return false; + } + + x *= dpr; + y *= dpr; + width *= dpr; + height *= dpr; + + auto x11 = getX11Api(); + + // Make sure something has changed, otherwise XIfEvent will block and + // freeze the emulator. + XWindowAttributes attrs; + if (!x11->XGetWindowAttributes(s_display, p_sub_window, &attrs)) { + return false; + } + if (x == attrs.x && y == attrs.y && width == attrs.width && height == attrs.height) { + // Technically, resizing was a success because it was unneeded. + return true; + } + + // This prevents flicker on resize. + x11->XSetWindowBackgroundPixmap(s_display, p_sub_window, None); + + int ret = x11->XMoveResizeWindow(s_display, p_sub_window, x, y, width, height); + + XEvent e; + x11->XIfEvent(s_display, &e, WaitForConfigureNotify, (char*)p_sub_window); + + return ret; +} + +void* getNativeDisplay() { return s_display; } diff --git a/host/renderControl_dec/BUILD.bazel b/host/renderControl_dec/BUILD.bazel index 32cdb8509..4f506dfbf 100644 --- a/host/renderControl_dec/BUILD.bazel +++ b/host/renderControl_dec/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -22,6 +22,7 @@ cc_library( copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, includes = ["."], + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ "//common/logging:gfxstream_common_logging", "//host/decoder_common:gfxstream_host_decoder_common", diff --git a/host/render_lib_impl.cpp b/host/render_lib_impl.cpp index 3e9ef95c2..45681f48c 100644 --- a/host/render_lib_impl.cpp +++ b/host/render_lib_impl.cpp @@ -132,9 +132,7 @@ bool RenderLibImpl::getOpt(RenderOpt* opt) { } #if GFXSTREAM_ENABLE_HOST_GLES - opt->display = fb->getDisplay(); - opt->surface = fb->getWindowSurface(); - opt->config = fb->getConfig(); + fb->getRenderOpt(opt); #endif return (opt->display && opt->surface && opt->config); } diff --git a/host/render_thread.cpp b/host/render_thread.cpp index 055a2a872..050077b3e 100644 --- a/host/render_thread.cpp +++ b/host/render_thread.cpp @@ -224,6 +224,7 @@ bool RenderThread::saveSnapshot(const SnapshotObjects& objects) { } void RenderThread::waitForFinished() { + mDecodersShouldStop.store(true, std::memory_order_relaxed); AutoLock lock(mLock); while (!mFinished.load(std::memory_order_relaxed)) { mFinishedSignal.wait(&lock); @@ -284,7 +285,7 @@ intptr_t RenderThread::main() { // initialize decoders #if GFXSTREAM_ENABLE_HOST_GLES if (FrameBuffer::getFB()->hasEmulationGl()) { - tInfo->initGl(); + tInfo->initGl(FrameBuffer::getFB()->getEmulationGl()); } initRenderControlContext(&(tInfo->m_rcDec)); diff --git a/host/render_thread_info.cpp b/host/render_thread_info.cpp index dc600209e..b533d5e53 100644 --- a/host/render_thread_info.cpp +++ b/host/render_thread_info.cpp @@ -63,9 +63,7 @@ void RenderThreadInfo::forAllRenderThreadInfos(std::functiongetBe32() == 1; if (loadGlInfo) { if (!m_glInfo) { - m_glInfo.emplace(); + m_glInfo.emplace(FrameBuffer::getFB()->getEmulationGl()); } if (!m_glInfo->onLoad(stream)) { return false; diff --git a/host/render_thread_info.h b/host/render_thread_info.h index 838996b2f..88b38f432 100644 --- a/host/render_thread_info.h +++ b/host/render_thread_info.h @@ -31,6 +31,7 @@ namespace gfxstream { namespace host { +class GlobalState; // A class used to model the state of each RenderThread related struct RenderThreadInfo { @@ -49,7 +50,7 @@ struct RenderThreadInfo { static void forAllRenderThreadInfos(std::function); #if GFXSTREAM_ENABLE_HOST_GLES - void initGl(); + void initGl(gl::EmulationGl* emulationGl); #endif // The unique id of owner guest process of this render thread diff --git a/host/render_window.cpp b/host/render_window.cpp index c06fd847a..173f09d6d 100644 --- a/host/render_window.cpp +++ b/host/render_window.cpp @@ -554,7 +554,7 @@ bool RenderWindow::setupSubWindow(FBNativeWindowType window, bool RenderWindow::removeSubWindow() { D("Entering mHasSubWindow=%s", mHasSubWindow ? "true" : "false"); if (!mHasSubWindow) { - return false; + return true; } mHasSubWindow = false; if (!useThread()) { diff --git a/host/renderdoc/BUILD.bazel b/host/renderdoc/BUILD.bazel index d7ae9c58d..56f86caa2 100644 --- a/host/renderdoc/BUILD.bazel +++ b/host/renderdoc/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -12,6 +12,7 @@ cc_library( copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, includes = ["include"], + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ "//common/logging:gfxstream_common_logging", "//host/library:gfxstream_host_library", @@ -26,6 +27,7 @@ cc_test( srcs = [ "renderdoc_unittest.cpp", ], + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ ":gfxstream_host_renderdoc", "//host/library:gfxstream_host_library", diff --git a/host/renderer_impl.cpp b/host/renderer_impl.cpp index 3b9d457e9..7c7322705 100644 --- a/host/renderer_impl.cpp +++ b/host/renderer_impl.cpp @@ -370,15 +370,15 @@ void RendererImpl::resumeAll() { repaintOpenGLDisplay(); } -void RendererImpl::save(gfxstream::Stream* stream, +bool RendererImpl::save(gfxstream::Stream* stream, const ITextureSaverPtr& textureSaver) { stream->putByte(mStopped); if (mStopped) { - return; + return true; } auto fb = FrameBuffer::getFB(); assert(fb); - fb->onSave(stream, textureSaver); + return fb->onSave(stream, textureSaver); } bool RendererImpl::load(gfxstream::Stream* stream, diff --git a/host/renderer_impl.h b/host/renderer_impl.h index 9944ac98f..c41a18113 100644 --- a/host/renderer_impl.h +++ b/host/renderer_impl.h @@ -106,7 +106,7 @@ class RendererImpl final : public Renderer { void pauseAllPreSave() final; void resumeAll() final; - void save(gfxstream::Stream* stream, + bool save(gfxstream::Stream* stream, const ITextureSaverPtr& textureSaver) final; bool load(gfxstream::Stream* stream, const ITextureLoaderPtr& textureLoader) final; diff --git a/host/snapshot/Android.bp b/host/snapshot/Android.bp deleted file mode 100644 index c4f737627..000000000 --- a/host/snapshot/Android.bp +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2025 The Android Open Source Project -// -// 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 expresso or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package { - default_applicable_licenses: ["hardware_google_gfxstream_license"], -} - -cc_library_static { - name: "libgfxstream_host_snapshot", - defaults: ["gfxstream_host_cc_defaults"], - header_libs: [ - "libgfxstream_backend_headers", - ], - export_header_lib_headers: [ - "libgfxstream_backend_headers", - ], - export_include_dirs: ["include"], -} diff --git a/host/snapshot/BUILD.bazel b/host/snapshot/BUILD.bazel deleted file mode 100644 index d77cec667..000000000 --- a/host/snapshot/BUILD.bazel +++ /dev/null @@ -1,20 +0,0 @@ -load("@rules_cc//cc:defs.bzl", "cc_library") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") - -package( - default_applicable_licenses = ["//:gfxstream_license"], - default_visibility = ["//:gfxstream"], -) - -cc_library( - name = "gfxstream_host_snapshot", - hdrs = [ - "include/snapshot/LazySnapshotObj.h", - ], - copts = GFXSTREAM_HOST_COPTS, - defines = GFXSTREAM_HOST_DEFINES, - strip_include_prefix = "include", - deps = [ - "//host:gfxstream_backend_headers", - ], -) diff --git a/host/snapshot/CMakeLists.txt b/host/snapshot/CMakeLists.txt deleted file mode 100644 index b963fb2c7..000000000 --- a/host/snapshot/CMakeLists.txt +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright 2025 The Android Open Source Project -# -# 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. - -add_library( - gfxstream_host_snapshot.headers - INTERFACE) -target_include_directories( - gfxstream_host_snapshot.headers - INTERFACE - include) -target_link_libraries( - gfxstream_host_snapshot.headers - INTERFACE - gfxstream_backend_headers) diff --git a/host/snapshot/meson.build b/host/snapshot/meson.build deleted file mode 100644 index b320ced48..000000000 --- a/host/snapshot/meson.build +++ /dev/null @@ -1,4 +0,0 @@ -# Copyright 2025 Android Open Source Project -# SPDX-License-Identifier: Apache-2.0 - -inc_host_snapshot = include_directories('include') diff --git a/host/testlibs/oswindow/BUILD.bazel b/host/testlibs/oswindow/BUILD.bazel index a4297aa4e..3721b918c 100644 --- a/host/testlibs/oswindow/BUILD.bazel +++ b/host/testlibs/oswindow/BUILD.bazel @@ -13,7 +13,7 @@ # limitations under the License. load("@rules_cc//cc:defs.bzl", "cc_library") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -54,6 +54,7 @@ cc_library( }), copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, + linkopts = GFXSTREAM_HOST_LINKOPTS, strip_include_prefix = "include", deps = [ "//common/logging:gfxstream_common_logging", diff --git a/host/testlibs/support/Android.bp b/host/testlibs/support/Android.bp index 2a3b54922..f7cf45d3a 100644 --- a/host/testlibs/support/Android.bp +++ b/host/testlibs/support/Android.bp @@ -46,7 +46,6 @@ cc_test_library { "libgfxstream_common_logging", "libgfxstream_host_decoder_common", "libgfxstream_host_iostream", - "libgfxstream_host_snapshot", "libgfxstream_oswindow_test_support", "libgmock", ], diff --git a/host/testlibs/support/BUILD.bazel b/host/testlibs/support/BUILD.bazel index 7ad310cc5..98a53880f 100644 --- a/host/testlibs/support/BUILD.bazel +++ b/host/testlibs/support/BUILD.bazel @@ -13,7 +13,7 @@ # limitations under the License. load("@rules_cc//cc:defs.bzl", "cc_library") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -36,12 +36,12 @@ cc_library( hdrs = glob(["include/**/*.h"]), copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, + linkopts = GFXSTREAM_HOST_LINKOPTS, strip_include_prefix = "include", deps = [ "//common/base:gfxstream_common_base", "//host:gfxstream_backend_headers", "//host:gfxstream_backend_static", - "//host:gfxstream_host_headers", "//host/common:gfxstream_host_common", "//host/decoder_common:gfxstream_host_decoder_common", "//host/features:gfxstream_host_features", diff --git a/host/testlibs/support/SampleApplication.cpp b/host/testlibs/support/SampleApplication.cpp index e51276413..e965e4776 100644 --- a/host/testlibs/support/SampleApplication.cpp +++ b/host/testlibs/support/SampleApplication.cpp @@ -265,7 +265,7 @@ SampleApplication::SampleApplication(int windowWidth, int windowHeight, int refr } mRenderThreadInfo.reset(new RenderThreadInfo()); - mRenderThreadInfo->initGl(); + mRenderThreadInfo->initGl(mFb->getEmulationGl()); mColorBuffer = mFb->createColorBuffer(mWidth, mHeight, GfxstreamFormat::R8G8B8A8_UNORM); mContext = mFb->createEmulatedEglContext(0, 0, glVersion); diff --git a/host/testlibs/support/include/gfxstream/host/testing/SampleApplication.h b/host/testlibs/support/include/gfxstream/host/testing/SampleApplication.h index 93d1a19c8..c833b8c7e 100644 --- a/host/testlibs/support/include/gfxstream/host/testing/SampleApplication.h +++ b/host/testlibs/support/include/gfxstream/host/testing/SampleApplication.h @@ -18,14 +18,14 @@ #include #include -#include "host/frame_buffer.h" -#include "host/hwc2.h" #include "OpenGLESDispatch/GLESv2Dispatch.h" -#include "host/render_thread_info.h" #include "gfxstream/Compiler.h" +#include "gfxstream/host/hwc2.h" #include "gfxstream/host/testing/OSWindow.h" +#include "host/frame_buffer.h" #include "host/gl/emulated_egl_context.h" #include "host/gl/emulated_egl_fence_sync.h" +#include "host/render_thread_info.h" namespace gfxstream { namespace host { diff --git a/host/tests/BUILD.bazel b/host/tests/BUILD.bazel index 283b43f14..c80cae3ca 100644 --- a/host/tests/BUILD.bazel +++ b/host/tests/BUILD.bazel @@ -13,6 +13,7 @@ # limitations under the License. load("@rules_cc//cc:defs.bzl", "cc_test") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -38,9 +39,11 @@ cc_test( "GLSnapshotVertexAttributes_unittest.cpp", "GLSnapshot_unittest.cpp", ], + copts = GFXSTREAM_HOST_COPTS, + defines = GFXSTREAM_HOST_DEFINES, + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ "//host:gfxstream_backend_static", - "//host:gfxstream_host_headers", "//host/decoder_common:gfxstream_host_decoder_common", "//host/testlibs/oswindow:gfxstream_oswindow_test_support", "//host/testlibs/support:gfxstream_host_testing_support", diff --git a/host/tests/DefaultFramebufferBlit_unittest.cpp b/host/tests/DefaultFramebufferBlit_unittest.cpp index d9c1e5345..b351cbe30 100644 --- a/host/tests/DefaultFramebufferBlit_unittest.cpp +++ b/host/tests/DefaultFramebufferBlit_unittest.cpp @@ -160,7 +160,7 @@ class ClearColor final : public SampleApplication { mFb->readColorBuffer( mColorBuffer, 0, 0, mWidth, mHeight, - GfxstreamFormat::R8G8B8A8_UNORM, forRead.data()); + GfxstreamFormat::R8G8B8A8_UNORM, forRead.data(), forRead.size()); EXPECT_TRUE( ImageMatches(mWidth, mHeight, 4, mWidth, targetBuffer.data(), forRead.data())); diff --git a/host/tests/GLSnapshotPrograms_unittest.cpp b/host/tests/GLSnapshotPrograms_unittest.cpp index 7bfc11d32..ad3c08aa9 100644 --- a/host/tests/GLSnapshotPrograms_unittest.cpp +++ b/host/tests/GLSnapshotPrograms_unittest.cpp @@ -114,7 +114,7 @@ class SnapshotGlProgramTest : public SnapshotPreserveTest { currentState.maxAttributeName); ASSERT_EQ(m_program_state.attributes.size(), currentState.attributes.size()); - for (int i = 0; i < currentState.attributes.size(); i++) { + for (size_t i = 0; i < currentState.attributes.size(); i++) { SCOPED_TRACE("active attribute i = " + std::to_string(i)); EXPECT_EQ(m_program_state.attributes[i].size, currentState.attributes[i].size); @@ -132,7 +132,7 @@ class SnapshotGlProgramTest : public SnapshotPreserveTest { EXPECT_EQ(m_program_state.maxUniformName, currentState.maxUniformName); ASSERT_EQ(m_program_state.uniforms.size(), currentState.uniforms.size()); - for (int i = 0; i < currentState.uniforms.size(); i++) { + for (size_t i = 0; i < currentState.uniforms.size(); i++) { SCOPED_TRACE("active uniform i = " + std::to_string(i)); EXPECT_EQ(m_program_state.uniforms[i].size, currentState.uniforms[i].size); @@ -225,7 +225,7 @@ class SnapshotGlProgramTest : public SnapshotPreserveTest { EXPECT_GE(ret.maxUniformName, 0); gl->glGetProgramiv(m_program_name, GL_ACTIVE_UNIFORMS, &ret.activeUniforms); - for (GLuint i = 0; i < ret.activeUniforms; i++) { + for (GLint i = 0; i < ret.activeUniforms; i++) { GlShaderVariable unif = {}; unif.name.resize(ret.maxUniformName); GLsizei unifLen; @@ -260,7 +260,7 @@ class SnapshotGlProgramTest : public SnapshotPreserveTest { EXPECT_GE(ret.maxAttributeName, 0); gl->glGetProgramiv(m_program_name, GL_ACTIVE_ATTRIBUTES, &ret.activeAttributes); - for (GLuint i = 0; i < ret.activeAttributes; i++) { + for (GLint i = 0; i < ret.activeAttributes; i++) { GlShaderVariable attr = {}; attr.name.resize(ret.maxAttributeName); GLsizei attrLen; diff --git a/host/tests/GLSnapshotRenderbuffers_unittest.cpp b/host/tests/GLSnapshotRenderbuffers_unittest.cpp index ae827af91..261017c8b 100644 --- a/host/tests/GLSnapshotRenderbuffers_unittest.cpp +++ b/host/tests/GLSnapshotRenderbuffers_unittest.cpp @@ -137,13 +137,14 @@ TEST_P(SnapshotGlRenderbufferFormatTest, SetFormat) { GLint maxSize; gl->glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &maxSize); m_state = GetParam(); - if (maxSize < m_state.width || maxSize < m_state.height) { + if (static_cast(maxSize) < m_state.width || + static_cast(maxSize) < m_state.height) { fprintf(stderr, "test dimensions exceed max renderbuffer size %d; " "using max size instead\n", maxSize); - m_state.width = maxSize; - m_state.height = maxSize; + m_state.width = static_cast(maxSize); + m_state.height = static_cast(maxSize); } gl->glRenderbufferStorage(GL_RENDERBUFFER, m_state.format.name, m_state.width, m_state.height); diff --git a/host/tests/GLSnapshotTextures_unittest.cpp b/host/tests/GLSnapshotTextures_unittest.cpp index 3194d704d..c007deef2 100644 --- a/host/tests/GLSnapshotTextures_unittest.cpp +++ b/host/tests/GLSnapshotTextures_unittest.cpp @@ -201,7 +201,7 @@ class SnapshotGlTextureUnitActiveTest : public SnapshotPreserveTest { &maxTextureUnits); EXPECT_EQ(GL_NO_ERROR, gl->glGetError()); - if (unit < maxTextureUnits) { + if (unit < static_cast(maxTextureUnits)) { m_active_texture_unit = unit; } else { fprintf(stderr, @@ -269,12 +269,12 @@ class SnapshotGlTextureUnitBindingsTest : public SnapshotPreserveTest { GLint maxTextureUnits; gl->glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits); - if (unit >= maxTextureUnits) { + if (unit >= static_cast(maxTextureUnits)) { fprintf(stderr, "Cannot bind to unit %d: max units is %d. Binding to %d " "instead.\n", unit, maxTextureUnits, maxTextureUnits - 1); - unit = maxTextureUnits - 1; + unit = static_cast(maxTextureUnits) - 1; } GLuint testTexture; @@ -330,9 +330,8 @@ class SnapshotGlTextureObjectTest : public SnapshotPreserveTest { EXPECT_TRUE(compareParameter(GL_TEXTURE_WRAP_S, m_state.wrapS)); EXPECT_TRUE(compareParameter(GL_TEXTURE_WRAP_T, m_state.wrapT)); - auto compareImageFunc = [this](GLenum imageTarget, - GlMipmapArray& levels) { - for (int i = 0; i < levels.size(); i++) { + auto compareImageFunc = [this](GLenum imageTarget, GlMipmapArray& levels) { + for (size_t i = 0; i < levels.size(); i++) { EXPECT_TRUE(compareVector( levels[i].bytes, getTextureImageData(gl, m_object_name, imageTarget, i, @@ -354,7 +353,7 @@ class SnapshotGlTextureObjectTest : public SnapshotPreserveTest { << " 'sides' of data."; break; } - for (int j = 0; j < m_state.imagesCubeMap.size(); j++) { + for (size_t j = 0; j < m_state.imagesCubeMap.size(); j++) { compareImageFunc(kGLES2TextureCubeMapSides[j], m_state.imagesCubeMap[j]); } @@ -382,7 +381,7 @@ class SnapshotGlTextureObjectTest : public SnapshotPreserveTest { gl->glTexParameteri(m_state.target, GL_TEXTURE_WRAP_T, m_state.wrapT); auto initImageFunc = [this](GLenum imageTarget, GlMipmapArray& levels) { - for (int i = 0; i < levels.size(); i++) { + for (size_t i = 0; i < levels.size(); i++) { levels[i].bytes.resize( levels[i].width * levels[i].height * glUtilsPixelBitSize( @@ -407,7 +406,7 @@ class SnapshotGlTextureObjectTest : public SnapshotPreserveTest { << " 'sides' of data."; break; } - for (int j = 0; j < m_state.imagesCubeMap.size(); j++) { + for (size_t j = 0; j < m_state.imagesCubeMap.size(); j++) { GLenum side = kGLES2TextureCubeMapSides[j]; initImageFunc(side, m_state.imagesCubeMap[j]); } diff --git a/host/tests/GLSnapshotVertexAttributes_unittest.cpp b/host/tests/GLSnapshotVertexAttributes_unittest.cpp index 98324467c..962210490 100644 --- a/host/tests/GLSnapshotVertexAttributes_unittest.cpp +++ b/host/tests/GLSnapshotVertexAttributes_unittest.cpp @@ -76,7 +76,7 @@ class SnapshotGlVertexAttributesTest GLint maxAttribs; gl->glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxAttribs); EXPECT_EQ(GL_NO_ERROR, gl->glGetError()); - if (index >= maxAttribs) { + if (index >= static_cast(maxAttribs)) { fprintf(stderr, "cannot select index %d: GL_MAX_VERTEX_ATTRIBS is %d.\n", index, maxAttribs); diff --git a/host/tracing/BUILD.bazel b/host/tracing/BUILD.bazel index cc5f4eff4..af6028616 100644 --- a/host/tracing/BUILD.bazel +++ b/host/tracing/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -13,5 +13,6 @@ cc_library( copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, includes = ["include"], + linkopts = GFXSTREAM_HOST_LINKOPTS, strip_include_prefix = "include", ) diff --git a/host/virtio_gpu_frontend.cpp b/host/virtio_gpu_frontend.cpp index 622406467..3b5eaaf16 100644 --- a/host/virtio_gpu_frontend.cpp +++ b/host/virtio_gpu_frontend.cpp @@ -24,15 +24,15 @@ #include #endif // ifdef GFXSTREAM_BUILD_WITH_SNAPSHOT_FRONTEND_SUPPORT +#include + #include #include #include -#include - #include "frame_buffer.h" -#include "framework_formats.h" #include "gfxstream/host/address_space_operations.h" +#include "gfxstream/host/framework_formats.h" #include "vulkan/vk_common_operations.h" // TODO: remove after moving save/load interface to ops. #include "gfxstream/common/logging.h" @@ -1067,7 +1067,10 @@ int VirtioGpuFrontend::snapshotRenderer(const char* directory) { GFXSTREAM_ERROR("Failed to snapshot renderer: renderer not available."); return -EINVAL; } - mRenderer->save(&stream, nullptr); + if (!mRenderer->save(&stream, nullptr)) { + GFXSTREAM_ERROR("Failed to snapshot renderer: mRenderer->save failed."); + return -EINVAL; + } return 0; } diff --git a/host/virtio_gpu_gfxstream_renderer.cpp b/host/virtio_gpu_gfxstream_renderer.cpp index a8a1768d1..250f106d6 100644 --- a/host/virtio_gpu_gfxstream_renderer.cpp +++ b/host/virtio_gpu_gfxstream_renderer.cpp @@ -596,6 +596,7 @@ VG_EXPORT int stream_renderer_init(struct stream_renderer_param* stream_renderer {STREAM_RENDERER_PARAM_WIN0_WIDTH, "WIN0_WIDTH"}, {STREAM_RENDERER_PARAM_WIN0_HEIGHT, "WIN0_HEIGHT"}, {STREAM_RENDERER_PARAM_DEBUG_CALLBACK, "DEBUG_CALLBACK"}, + {STREAM_RENDERER_PARAM_DEBUG_CALLBACK_EX, "DEBUG_CALLBACK_EX"}, {STREAM_RENDERER_SKIP_OPENGLES_INIT, "SKIP_OPENGLES_INIT"}, }; @@ -626,6 +627,7 @@ VG_EXPORT int stream_renderer_init(struct stream_renderer_param* stream_renderer std::string renderer_features_str; stream_renderer_fence_callback fence_callback = nullptr; stream_renderer_debug_callback log_callback = nullptr; + stream_renderer_debug_callback_ex log_callback_ex = nullptr; bool rendererInitializedExternally = false; // Iterate all parameters that we support. @@ -676,6 +678,12 @@ VG_EXPORT int stream_renderer_init(struct stream_renderer_param* stream_renderer static_cast(param.value)); break; } + case STREAM_RENDERER_PARAM_DEBUG_CALLBACK_EX: { + GFXSTREAM_DEBUG("STREAM_RENDERER_PARAM_DEBUG_CALLBACK_EX passed"); + log_callback_ex = reinterpret_cast( + static_cast(param.value)); + break; + } case STREAM_RENDERER_SKIP_OPENGLES_INIT: { // AEMU currently does its own initialization in // qemu/android/android-emu/android/opengles.cpp. @@ -697,7 +705,47 @@ VG_EXPORT int stream_renderer_init(struct stream_renderer_param* stream_renderer } } - if (log_callback) { + if (log_callback_ex) { + gfxstream::host::SetGfxstreamLogCallback([log_callback_ex, log_user_data = renderer_cookie]( + LogLevel level, const char* file, int line, + const char* function, const char* message) { + stream_renderer_debug_ex log_info = { + .file = file, + .line = line, + .function = function, + .message = message, + }; + + switch (level) { + case LogLevel::kFatal: { + log_info.debug_type = STREAM_RENDERER_DEBUG_ERROR; + break; + } + case LogLevel::kError: { + log_info.debug_type = STREAM_RENDERER_DEBUG_ERROR; + break; + } + case LogLevel::kWarning: { + log_info.debug_type = STREAM_RENDERER_DEBUG_WARN; + break; + } + case LogLevel::kInfo: { + log_info.debug_type = STREAM_RENDERER_DEBUG_INFO; + break; + } + case LogLevel::kDebug: { + log_info.debug_type = STREAM_RENDERER_DEBUG_DEBUG; + break; + } + case LogLevel::kVerbose: { + log_info.debug_type = STREAM_RENDERER_DEBUG_DEBUG; + break; + } + } + + log_callback_ex(log_user_data, &log_info); + }); + } else if (log_callback) { gfxstream::host::SetGfxstreamLogCallback([log_callback, log_user_data = renderer_cookie]( LogLevel level, const char* file, int line, const char* function, const char* message) { diff --git a/host/virtio_gpu_resource.cpp b/host/virtio_gpu_resource.cpp index 6a146442b..66d929c91 100644 --- a/host/virtio_gpu_resource.cpp +++ b/host/virtio_gpu_resource.cpp @@ -323,8 +323,8 @@ int VirtioGpuResource::ImportHandle(const struct stream_renderer_handle* handle, switch (handle->handle_type) { #if GFXSTREAM_ENABLE_HOST_GLES case STREAM_HANDLE_TYPE_PLATFORM_EGL_NATIVE_PIXMAP: - importSuccess = colorBufferPtr->glOpImportEglNativePixmap( - reinterpret_cast(handle->os_handle), preserveContent); + importSuccess = colorBufferPtr->importHandle(reinterpret_cast(handle->os_handle), + preserveContent); break; #endif default: diff --git a/host/vulkan/Android.bp b/host/vulkan/Android.bp index e8e98b4fd..7cf425717 100644 --- a/host/vulkan/Android.bp +++ b/host/vulkan/Android.bp @@ -47,9 +47,9 @@ cc_library_static { "libgfxstream_host_library", "libgfxstream_host_openglesdispatch", "libgfxstream_host_renderdoc", - "libgfxstream_host_snapshot", "libgfxstream_host_vulkan_cereal", "libgfxstream_host_vulkan_emulatedtextures", + "libgfxstream_host_native_window", ], export_static_lib_headers: [ "libgfxstream_host_decoder_common", @@ -67,7 +67,6 @@ cc_library_static { "-Wno-unreachable-code-loop-increment", ], srcs: [ - "borrowed_image_vk.cpp", "buffer_vk.cpp", "color_buffer_vk.cpp", "compositor_vk.cpp", diff --git a/host/vulkan/BUILD.bazel b/host/vulkan/BUILD.bazel index b48c2a8a7..dc2c8a7a2 100644 --- a/host/vulkan/BUILD.bazel +++ b/host/vulkan/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -11,6 +11,7 @@ cc_library( copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, includes = ["."], + linkopts = GFXSTREAM_HOST_LINKOPTS, textual_hdrs = [ "vk_android_native_buffer_gfxstream.h", "vk_android_native_buffer_structure_type.h", @@ -41,6 +42,7 @@ cc_library( copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, includes = ["."], + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ ":gfxstream_vulkan_headers", "//common/base:gfxstream_common_base", @@ -59,7 +61,6 @@ cc_library( cc_library( name = "gfxstream_vulkan_server", srcs = [ - "borrowed_image_vk.cpp", "buffer_vk.cpp", "color_buffer_vk.cpp", "compositor_vk.cpp", @@ -91,7 +92,6 @@ cc_library( "vulkan_stream.cpp", ], hdrs = [ - "borrowed_image_vk.h", "buffer_vk.h", "color_buffer_vk.h", "compositor_fragment_shader.h", @@ -143,7 +143,7 @@ cc_library( "cereal", "cereal/common", ], - linkopts = select({ + linkopts = GFXSTREAM_HOST_LINKOPTS + select({ "@platforms//os:windows": [ "-DEFAULTLIB:Advapi32.lib", ], @@ -158,7 +158,6 @@ cc_library( "//common/logging:gfxstream_common_logging", "//common/utils:gfxstream_common_utils", "//host:gfxstream_backend_headers", - "//host:gfxstream_host_headers", "//host/common:gfxstream_host_common", "//host/compressed_textures:gfxstream_host_compressed_textures", "//host/decoder_common:gfxstream_host_decoder_common", @@ -166,6 +165,7 @@ cc_library( "//host/gl/OpenGLESDispatch:gfxstream_host_openglesdispatch_headers", "//host/iostream:gfxstream_host_iostream", "//host/library:gfxstream_host_library", + "//host/native_window:gfxstream_host_native_window", "//host/renderdoc:gfxstream_host_renderdoc", "//host/tracing:gfxstream_host_tracing", "//host/vulkan/cereal:gfxstream_vulkan_cereal", @@ -214,6 +214,7 @@ cc_test( "testdata/256x256_golden_transform_rot270.png", "testdata/256x256_golden_transform_rot90.png", ], + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ ":gfxstream_vulkan_server", "//common/base:gfxstream_common_base", @@ -233,10 +234,10 @@ cc_test( "display_vk_unittest.cpp", ], copts = GFXSTREAM_HOST_COPTS, + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ ":gfxstream_vulkan_server", "//common/base:gfxstream_common_base", - "//host:gfxstream_host_headers", "//host/testlibs/oswindow:gfxstream_oswindow_test_support", "//host/testlibs/support:gfxstream_host_testing_support", "@com_google_googletest//:gtest", @@ -250,6 +251,7 @@ cc_test( "vk_format_utils_unittest.cpp", ], copts = GFXSTREAM_HOST_COPTS, + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ ":gfxstream_vulkan_server", "//common/base:gfxstream_common_base", @@ -265,6 +267,7 @@ cc_test( "vk_common_operations_tests.cpp", ], copts = GFXSTREAM_HOST_COPTS, + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ ":gfxstream_vulkan_server", "//common/base:gfxstream_common_base", @@ -282,10 +285,10 @@ cc_test( "vk_emulated_physical_device_memory_tests.cpp", ], copts = GFXSTREAM_HOST_COPTS, + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ ":gfxstream_vulkan_server", "//common/base:gfxstream_common_base", - "//host:gfxstream_host_headers", "//host/features:gfxstream_host_features", "//host/testlibs/support:gfxstream_host_testing_support", "@com_google_googletest//:gtest", @@ -299,10 +302,10 @@ cc_test( "vk_emulated_physical_device_queue_tests.cpp", ], copts = GFXSTREAM_HOST_COPTS, + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ ":gfxstream_vulkan_server", "//common/base:gfxstream_common_base", - "//host:gfxstream_host_headers", "//host/features:gfxstream_host_features", "//host/testlibs/support:gfxstream_host_testing_support", "//third_party/vulkan:gfxstream_vulkan_headers", diff --git a/host/vulkan/CMakeLists.txt b/host/vulkan/CMakeLists.txt index 68e9fa13d..bb73f00c7 100644 --- a/host/vulkan/CMakeLists.txt +++ b/host/vulkan/CMakeLists.txt @@ -21,7 +21,6 @@ if(CONFIG_AEMU) endif() add_library(gfxstream-vulkan-server - borrowed_image_vk.cpp buffer_vk.cpp color_buffer_vk.cpp compositor_vk.cpp @@ -67,12 +66,12 @@ target_link_libraries(gfxstream-vulkan-server PUBLIC gfxstream_host_iostream gfxstream_host_library gfxstream_host_renderdoc - gfxstream_host_snapshot.headers gfxstream_host_tracing gfxstream_openglesdispatch.headers gfxstream_vulkan_headers gfxstream_xcb_headers OpenglRender_vulkan_cereal + gfxstream_host_native_window PRIVATE gfxstream_opengl_headers ) diff --git a/host/vulkan/borrowed_image_vk.cpp b/host/vulkan/borrowed_image_vk.cpp deleted file mode 100644 index 04f19a1a3..000000000 --- a/host/vulkan/borrowed_image_vk.cpp +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2022 The Android Open Source Project -// -// 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 expresso or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "borrowed_image_vk.h" - -namespace gfxstream { -namespace host { -namespace vk { - -void addNeededBarriersToUseBorrowedImage( - const BorrowedImageInfoVk& borrowedImageInfo, uint32_t usedQueueFamilyIndex, - VkImageLayout usedInitialImageLayout, VkImageLayout usedFinalImageLayout, - VkAccessFlags usedAccessMask, std::vector* preUseQueueTransferBarriers, - std::vector* preUseLayoutTransitionBarriers, - std::vector* postUseLayoutTransitionBarriers, - std::vector* postUseQueueTransferBarriers) { - if (borrowedImageInfo.preBorrowQueueFamilyIndex != usedQueueFamilyIndex) { - const VkImageMemoryBarrier queueTransferBarrier = { - .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - .pNext = nullptr, - .srcAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, - .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, - .oldLayout = borrowedImageInfo.preBorrowLayout, - .newLayout = borrowedImageInfo.preBorrowLayout, - .srcQueueFamilyIndex = borrowedImageInfo.preBorrowQueueFamilyIndex, - .dstQueueFamilyIndex = usedQueueFamilyIndex, - .image = borrowedImageInfo.image, - .subresourceRange = - { - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .baseMipLevel = 0, - .levelCount = 1, - .baseArrayLayer = 0, - .layerCount = 1, - }, - }; - preUseQueueTransferBarriers->emplace_back(queueTransferBarrier); - } - if (borrowedImageInfo.preBorrowLayout != usedInitialImageLayout && - usedInitialImageLayout != VK_IMAGE_LAYOUT_UNDEFINED) { - const VkImageMemoryBarrier layoutTransitionBarrier = { - .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - .pNext = nullptr, - .srcAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, - .dstAccessMask = usedAccessMask, - .oldLayout = borrowedImageInfo.preBorrowLayout, - .newLayout = usedInitialImageLayout, - .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .image = borrowedImageInfo.image, - .subresourceRange = - { - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .baseMipLevel = 0, - .levelCount = 1, - .baseArrayLayer = 0, - .layerCount = 1, - }, - }; - preUseLayoutTransitionBarriers->emplace_back(layoutTransitionBarrier); - } - if (borrowedImageInfo.postBorrowLayout != usedFinalImageLayout) { - const VkImageMemoryBarrier layoutTransitionBarrier = { - .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - .pNext = nullptr, - .srcAccessMask = usedAccessMask, - .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, - .oldLayout = usedFinalImageLayout, - .newLayout = borrowedImageInfo.postBorrowLayout, - .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .image = borrowedImageInfo.image, - .subresourceRange = - { - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .baseMipLevel = 0, - .levelCount = 1, - .baseArrayLayer = 0, - .layerCount = 1, - }, - }; - postUseLayoutTransitionBarriers->emplace_back(layoutTransitionBarrier); - } - if (borrowedImageInfo.postBorrowQueueFamilyIndex != usedQueueFamilyIndex) { - const VkImageMemoryBarrier queueTransferBarrier = { - .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - .pNext = nullptr, - .srcAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, - .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, - .oldLayout = borrowedImageInfo.postBorrowLayout, - .newLayout = borrowedImageInfo.postBorrowLayout, - .srcQueueFamilyIndex = usedQueueFamilyIndex, - .dstQueueFamilyIndex = borrowedImageInfo.postBorrowQueueFamilyIndex, - .image = borrowedImageInfo.image, - .subresourceRange = - { - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .baseMipLevel = 0, - .levelCount = 1, - .baseArrayLayer = 0, - .layerCount = 1, - }, - }; - postUseQueueTransferBarriers->emplace_back(queueTransferBarrier); - } -} - -} // namespace vk -} // namespace host -} // namespace gfxstream diff --git a/host/vulkan/borrowed_image_vk.h b/host/vulkan/borrowed_image_vk.h deleted file mode 100644 index 25d1ebec2..000000000 --- a/host/vulkan/borrowed_image_vk.h +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2022 The Android Open Source Project -// -// 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 expresso or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include - -#include -#include - -#include "gfxstream/host/borrowed_image.h" -#include "gfxstream/host/gfxstream_format.h" - -namespace gfxstream { -namespace host { -namespace vk { - -struct BorrowedImageInfoVk : public BorrowedImageInfo { - VkImage image = VK_NULL_HANDLE; - VkImageView imageView = VK_NULL_HANDLE; - VkImageCreateInfo imageCreateInfo = {}; - GfxstreamFormat imageFormat = GfxstreamFormat::UNKNOWN; - - // The image layout that `image` is in before composition. - // - // This is currently ignored for composition target images as - // composition targets are expected to be cleared during - // composition. - VkImageLayout preBorrowLayout = VK_IMAGE_LAYOUT_UNDEFINED; - - // The queue family index that owns `image` before composition. - uint32_t preBorrowQueueFamilyIndex = 0; - - // The image layout that `image` should be transitioned to - // after composition. - // - // This is currently ignored for composition target images as - // composition targets are expected to be transitioned to - // VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL after composition for - // blitting to display images. - VkImageLayout postBorrowLayout = VK_IMAGE_LAYOUT_UNDEFINED; - - // The queue family index that `image` should be transitioned to - // after composition. - uint32_t postBorrowQueueFamilyIndex = 0; -}; - -// The caller should always record the queue transfer barriers with stages that supoort -// VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT. -void addNeededBarriersToUseBorrowedImage( - const BorrowedImageInfoVk& borrowedImageInfo, uint32_t usedQueueFamilyIndex, - VkImageLayout usedInitialImageLayout, VkImageLayout usedFinalImageLayout, - VkAccessFlags usedAccessMask, std::vector* preUseQueueTransferBarriers, - std::vector* preUseLayoutTransitionBarriers, - std::vector* postUseLayoutTransitionBarriers, - std::vector* postUseQueueTransferBarriers); - -} // namespace vk -} // namespace host -} // namespace gfxstream diff --git a/host/vulkan/cereal/BUILD.bazel b/host/vulkan/cereal/BUILD.bazel index 3ec615d28..378d8f71e 100644 --- a/host/vulkan/cereal/BUILD.bazel +++ b/host/vulkan/cereal/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -19,6 +19,7 @@ cc_library( copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, includes = ["common"], + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ "//common/base:gfxstream_common_base", "//common/logging:gfxstream_common_logging", @@ -51,10 +52,10 @@ cc_library( copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, includes = ["common"], + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ "//common/base:gfxstream_common_base", "//common/logging:gfxstream_common_logging", - "//host:gfxstream_host_headers", "//host/common:gfxstream_host_common", "//host/features:gfxstream_host_features", "//host/tracing:gfxstream_host_tracing", diff --git a/host/vulkan/color_buffer_vk.cpp b/host/vulkan/color_buffer_vk.cpp index e29cf175b..a24aaf3b2 100644 --- a/host/vulkan/color_buffer_vk.cpp +++ b/host/vulkan/color_buffer_vk.cpp @@ -107,12 +107,13 @@ bool ColorBufferVk::updateFromBytes(uint32_t x, uint32_t y, uint32_t w, uint32_t return mVkEmulation.updateColorBufferFromBytes(mHandle, x, y, w, h, bytes); } -std::unique_ptr ColorBufferVk::borrowForComposition(bool colorBufferIsTarget) { - return mVkEmulation.borrowColorBufferForComposition(mHandle, colorBufferIsTarget); +std::unique_ptr ColorBufferVk::prepareForComposition( + bool colorBufferIsTarget) { + return mVkEmulation.prepareColorBufferForComposition(mHandle, colorBufferIsTarget); } -std::unique_ptr ColorBufferVk::borrowForDisplay() { - return mVkEmulation.borrowColorBufferForDisplay(mHandle); +std::unique_ptr ColorBufferVk::prepareForDisplay() { + return mVkEmulation.prepareColorBufferForDisplay(mHandle); } std::optional ColorBufferVk::exportBlob() { diff --git a/host/vulkan/color_buffer_vk.h b/host/vulkan/color_buffer_vk.h index abb7d99af..e649d4fd8 100644 --- a/host/vulkan/color_buffer_vk.h +++ b/host/vulkan/color_buffer_vk.h @@ -12,12 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include +#pragma once + +#include #include #include -#include "gfxstream/host/borrowed_image.h" #include "gfxstream/host/external_object_manager.h" #include "gfxstream/host/gfxstream_format.h" #include "render-utils/Renderer.h" @@ -39,6 +40,20 @@ enum class LoadImageBehavior { class VkEmulation; +struct ColorBufferVkImageInfo { + uint32_t id = 0; + uint32_t width = 0; + uint32_t height = 0; + VkImage image = VK_NULL_HANDLE; + VkImageView imageView = VK_NULL_HANDLE; + VkImageCreateInfo imageCreateInfoShallow = {}; + GfxstreamFormat imageFormat = GfxstreamFormat::UNKNOWN; + VkImageLayout preBorrowLayout = VK_IMAGE_LAYOUT_UNDEFINED; + uint32_t preBorrowQueueFamilyIndex = 0; + VkImageLayout postBorrowLayout = VK_IMAGE_LAYOUT_UNDEFINED; + uint32_t postBorrowQueueFamilyIndex = 0; +}; + class ColorBufferVk { public: static std::unique_ptr create(VkEmulation& emulationVk, uint32_t handle, @@ -58,8 +73,8 @@ class ColorBufferVk { bool updateFromBytes(const std::vector& bytes); bool updateFromBytes(uint32_t x, uint32_t y, uint32_t w, uint32_t h, const void* bytes); - std::unique_ptr borrowForComposition(bool colorBufferIsTarget); - std::unique_ptr borrowForDisplay(); + std::unique_ptr prepareForComposition(bool colorBufferIsTarget); + std::unique_ptr prepareForDisplay(); void onLoad(gfxstream::Stream* stream, LoadImageBehavior behavior); void onSave(gfxstream::Stream* stream, SaveImageBehavior behavior); diff --git a/host/vulkan/compositor_vk.cpp b/host/vulkan/compositor_vk.cpp index fc2dc9c50..d95a146c4 100644 --- a/host/vulkan/compositor_vk.cpp +++ b/host/vulkan/compositor_vk.cpp @@ -15,18 +15,19 @@ #include "compositor_vk.h" #include +#include #include #include #include +#include "color_buffer_vk.h" +#include "compositor_fragment_shader.h" +#include "compositor_vertex_shader.h" #include "gfxstream/common/logging.h" #include "gfxstream/host/tracing.h" -#include "vulkan/compositor_fragment_shader.h" -#include "vulkan/compositor_vertex_shader.h" -#include "vulkan/vk_enum_string_helper.h" -#include "vulkan/vk_format_utils.h" -#include "vulkan/vk_utils.h" +#include "vk_format_utils.h" +#include "vk_utils.h" namespace gfxstream { namespace host { @@ -46,16 +47,6 @@ static const GfxstreamFormat kRenderTargetFormats[2] = { GfxstreamFormat::B8G8R8A8_UNORM, }; -const BorrowedImageInfoVk* getInfoOrAbort(const std::unique_ptr& info) { - auto imageVk = static_cast(info.get()); - if (imageVk != nullptr) { - return imageVk; - } - - GFXSTREAM_FATAL("CompositorVk did not find BorrowedImageInfoVk"); - return nullptr; -} - struct Vertex { alignas(8) glm::vec2 pos; alignas(8) glm::vec2 tex; @@ -1159,7 +1150,7 @@ VkFormatFeatureFlags CompositorVk::getFormatFeatures(VkFormat format, VkImageTil } CompositorVk::RenderTarget* CompositorVk::getOrCreateRenderTargetInfo( - const BorrowedImageInfoVk& imageInfo) { + const ColorBufferVkImageInfo& imageInfo) { std::lock_guard lock(m_renderTargetCacheMutex); auto* renderTargetPtr = m_renderTargetCache.get(imageInfo.id); if (renderTargetPtr != nullptr) { @@ -1174,9 +1165,10 @@ CompositorVk::RenderTarget* CompositorVk::getOrCreateRenderTargetInfo( } VkRenderPass renderPass = renderPassIt->second; - auto* renderTarget = new RenderTarget(m_vk, m_vkDevice, imageInfo.image, imageInfo.imageView, - imageInfo.imageCreateInfo.extent.width, - imageInfo.imageCreateInfo.extent.height, renderPass); + auto* renderTarget = + new RenderTarget(m_vk, m_vkDevice, imageInfo.image, imageInfo.imageView, + imageInfo.imageCreateInfoShallow.extent.width, + imageInfo.imageCreateInfoShallow.extent.height, renderPass); m_renderTargetCache.set(imageInfo.id, std::unique_ptr(renderTarget)); @@ -1196,13 +1188,13 @@ bool CompositorVk::canCompositeFrom(const VkImageCreateInfo& imageCi) { return true; } -void CompositorVk::buildCompositionVk(const CompositionRequest& compositionRequest, +void CompositorVk::buildCompositionVk(const CompositionRequestVk& compositionRequest, CompositionVk* compositionVk) { - if (compositionRequest.target.get() == nullptr) { + if (compositionRequest.target == nullptr) { GFXSTREAM_ERROR("invalid target!"); return; } - const BorrowedImageInfoVk* targetImage = getInfoOrAbort(compositionRequest.target); + const ColorBufferVkImageInfo* targetImage = compositionRequest.target; auto renderPassIt = m_vkRenderPasses.find(targetImage->imageFormat); if (renderPassIt == m_vkRenderPasses.end()) { @@ -1220,17 +1212,17 @@ void CompositorVk::buildCompositionVk(const CompositionRequest& compositionReque compositionVk->targetRenderPass = renderPassIt->second; compositionVk->targetFramebuffer = targetImageRenderTarget->m_vkFramebuffer; - for (const CompositionRequestLayer& layer : compositionRequest.layers) { + for (const CompositionRequestLayerVk& layer : compositionRequest.layers) { uint32_t sourceImageWidth = 0; uint32_t sourceImageHeight = 0; - const BorrowedImageInfoVk* sourceImage = nullptr; + const ColorBufferVkImageInfo* sourceImage = nullptr; if (layer.props.composeMode == HWC2_COMPOSITION_SOLID_COLOR) { sourceImageWidth = targetWidth; sourceImageHeight = targetHeight; } else if (layer.source) { - sourceImage = getInfoOrAbort(layer.source); - if (!canCompositeFrom(sourceImage->imageCreateInfo)) { + sourceImage = layer.source; + if (!canCompositeFrom(sourceImage->imageCreateInfoShallow)) { continue; } @@ -1391,8 +1383,55 @@ void CompositorVk::buildCompositionVk(const CompositionRequest& compositionReque } } +static Compositor::CompositionFinishedWaitable getCompletedFuture() { + std::promise promise; + promise.set_value(); + return promise.get_future().share(); +} + CompositorVk::CompositionFinishedWaitable CompositorVk::compose( const CompositionRequest& compositionRequest) { + auto targetCb = compositionRequest.target; + if (!targetCb) { + GFXSTREAM_ERROR("invalid target!"); + return getCompletedFuture(); + } + targetCb->invalidateForBackend(Backend::VK); + auto targetCbVk = targetCb->getColorBufferVk(); + auto targetImageInfo = targetCbVk ? targetCbVk->prepareForComposition(true) : nullptr; + if (!targetImageInfo) { + GFXSTREAM_ERROR("failed to prepare target!"); + return getCompletedFuture(); + } + + CompositionRequestVk compositionRequestVk; + compositionRequestVk.target = targetImageInfo.get(); + + std::vector> keepAliveImages; + keepAliveImages.push_back(std::move(targetImageInfo)); + + for (const CompositionRequestLayer& layer : compositionRequest.layers) { + CompositionRequestLayerVk layerVk; + layerVk.props = layer.props; + + if (layer.props.composeMode == HWC2_COMPOSITION_DEVICE && layer.source) { + auto sourceCb = layer.source; + sourceCb->invalidateForBackend(Backend::VK); + auto sourceCbVk = sourceCb->getColorBufferVk(); + auto sourceImageInfo = sourceCbVk ? sourceCbVk->prepareForComposition(false) : nullptr; + if (sourceImageInfo) { + layerVk.source = sourceImageInfo.get(); + keepAliveImages.push_back(std::move(sourceImageInfo)); + } + } + compositionRequestVk.layers.push_back(layerVk); + } + + return compose(compositionRequestVk); +} + +CompositorVk::CompositionFinishedWaitable CompositorVk::compose( + const CompositionRequestVk& compositionRequest) { static uint32_t sCompositionNumber = 0; const uint32_t thisCompositionNumber = sCompositionNumber++; @@ -1418,14 +1457,21 @@ CompositorVk::CompositionFinishedWaitable CompositorVk::compose( std::vector preCompositionLayoutTransitionBarriers; std::vector postCompositionLayoutTransitionBarriers; std::vector postCompositionQueueTransferBarriers; - addNeededBarriersToUseBorrowedImage( - *compositionVk.targetImage, m_queueFamilyIndex, kTargetImageInitialLayoutUsed, - kTargetImageFinalLayoutUsed, VK_ACCESS_MEMORY_WRITE_BIT, - &preCompositionQueueTransferBarriers, &preCompositionLayoutTransitionBarriers, - &postCompositionLayoutTransitionBarriers, &postCompositionQueueTransferBarriers); - for (const BorrowedImageInfoVk* sourceImage : compositionVk.layersSourceImages) { - addNeededBarriersToUseBorrowedImage( - *sourceImage, m_queueFamilyIndex, kSourceImageInitialLayoutUsed, + { + const auto* targetImage = compositionVk.targetImage; + vk_util::addNeededBarriersToUseImage( + targetImage->image, targetImage->preBorrowQueueFamilyIndex, + targetImage->preBorrowLayout, targetImage->postBorrowQueueFamilyIndex, + targetImage->postBorrowLayout, m_queueFamilyIndex, kTargetImageInitialLayoutUsed, + kTargetImageFinalLayoutUsed, VK_ACCESS_MEMORY_WRITE_BIT, + &preCompositionQueueTransferBarriers, &preCompositionLayoutTransitionBarriers, + &postCompositionLayoutTransitionBarriers, &postCompositionQueueTransferBarriers); + } + for (const ColorBufferVkImageInfo* sourceImage : compositionVk.layersSourceImages) { + vk_util::addNeededBarriersToUseImage( + sourceImage->image, sourceImage->preBorrowQueueFamilyIndex, + sourceImage->preBorrowLayout, sourceImage->postBorrowQueueFamilyIndex, + sourceImage->postBorrowLayout, m_queueFamilyIndex, kSourceImageInitialLayoutUsed, kSourceImageFinalLayoutUsed, VK_ACCESS_SHADER_READ_BIT, &preCompositionQueueTransferBarriers, &preCompositionLayoutTransitionBarriers, &postCompositionLayoutTransitionBarriers, &postCompositionQueueTransferBarriers); @@ -1490,8 +1536,8 @@ CompositorVk::CompositionFinishedWaitable CompositorVk::compose( }, .extent = { - .width = compositionVk.targetImage->imageCreateInfo.extent.width, - .height = compositionVk.targetImage->imageCreateInfo.extent.height, + .width = compositionVk.targetImage->imageCreateInfoShallow.extent.width, + .height = compositionVk.targetImage->imageCreateInfoShallow.extent.height, }, }, .clearValueCount = 1, @@ -1512,15 +1558,16 @@ CompositorVk::CompositionFinishedWaitable CompositorVk::compose( }, .extent = { - .width = compositionVk.targetImage->imageCreateInfo.extent.width, - .height = compositionVk.targetImage->imageCreateInfo.extent.height, + .width = compositionVk.targetImage->imageCreateInfoShallow.extent.width, + .height = compositionVk.targetImage->imageCreateInfoShallow.extent.height, }, }; const VkViewport viewport = { .x = 0.0f, .y = 0.0f, - .width = static_cast(compositionVk.targetImage->imageCreateInfo.extent.width), - .height = static_cast(compositionVk.targetImage->imageCreateInfo.extent.height), + .width = static_cast(compositionVk.targetImage->imageCreateInfoShallow.extent.width), + .height = + static_cast(compositionVk.targetImage->imageCreateInfoShallow.extent.height), .minDepth = 0.0f, .maxDepth = 1.0f, }; diff --git a/host/vulkan/compositor_vk.h b/host/vulkan/compositor_vk.h index a9e85f21f..295116d89 100644 --- a/host/vulkan/compositor_vk.h +++ b/host/vulkan/compositor_vk.h @@ -26,17 +26,16 @@ #include #include -#include "borrowed_image_vk.h" -#include "compositor.h" +#include "color_buffer_vk.h" #include "debug_utils_helper.h" #include "gfxstream/LruCache.h" -#include "gfxstream/host/borrowed_image.h" +#include "gfxstream/host/compositor.h" #include "gfxstream/host/gfxstream_format.h" +#include "gfxstream/host/hwc2.h" #include "gfxstream/synchronization/Lock.h" #include "goldfish_vk_dispatch.h" -#include "host/hwc2.h" -#include "vulkan/vk_format_support.h" -#include "vulkan/vk_utils.h" +#include "vk_format_support.h" +#include "vk_utils.h" namespace gfxstream { namespace host { @@ -267,6 +266,16 @@ struct CompositorVkBase : public vk_util::MultiCrtp layers; +}; + class CompositorVk : protected CompositorVkBase, public Compositor { public: static std::unique_ptr create( @@ -280,6 +289,8 @@ class CompositorVk : protected CompositorVkBase, public Compositor { CompositionFinishedWaitable compose(const CompositionRequest& compositionRequest) override; + CompositionFinishedWaitable compose(const CompositionRequestVk& compositionRequestVk); + void setScreenMask(int width, int height, const uint8_t* rgbaData) override; void setScreenBackground(int width, int height, const uint8_t* rgbaData) override; @@ -370,15 +381,15 @@ class CompositorVk : protected CompositorVkBase, public Compositor { // A consolidated view of a `Compositor::CompositionRequest` with only // the Vulkan components needed for command recording and submission. struct CompositionVk { - const BorrowedImageInfoVk* targetImage = nullptr; + const ColorBufferVkImageInfo* targetImage = nullptr; VkRenderPass targetRenderPass = VK_NULL_HANDLE; VkFramebuffer targetFramebuffer = VK_NULL_HANDLE; std::vector layersPipelines; std::vector layerSourceSamplerFormats; - std::vector layersSourceImages; + std::vector layersSourceImages; FrameDescriptorSetsContents layersDescriptorSets; }; - void buildCompositionVk(const CompositionRequest& compositionRequest, + void buildCompositionVk(const CompositionRequestVk& compositionRequest, CompositionVk* compositionVk); void updateDescriptorSetsIfChanged(const FrameDescriptorSetsContents& contents, @@ -406,7 +417,7 @@ class CompositorVk : protected CompositorVkBase, public Compositor { // Gets the RenderTarget used for composing into the given image if it already exists, // otherwise creates it. - RenderTarget* getOrCreateRenderTargetInfo(const BorrowedImageInfoVk& info); + RenderTarget* getOrCreateRenderTargetInfo(const ColorBufferVkImageInfo& info); // Cached format properties used for checking if composition is supported with a given // format. diff --git a/host/vulkan/compositor_vk_unittest.cpp b/host/vulkan/compositor_vk_unittest.cpp index f119a7d25..6b004a0f6 100644 --- a/host/vulkan/compositor_vk_unittest.cpp +++ b/host/vulkan/compositor_vk_unittest.cpp @@ -12,19 +12,19 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include +#include + #include "compositor_vk.h" #include #include #include +#include #include #include -#include -#include -#include - -#include "borrowed_image_vk.h" +#include "color_buffer_vk.h" #include "gfxstream/common/testing/graphics_test_environment.h" #include "gfxstream/host/testing/VkTestUtils.h" #include "gfxstream/image_utils.h" @@ -131,6 +131,7 @@ class CompositorVkTest : public ::testing::Test { } void TearDown() override { + m_allocatedImages.clear(); m_YcbcrSamplerPool.destroy(); k_vk->vkDestroyCommandPool(m_vkDevice, m_vkCommandPool, nullptr); k_vk->vkDestroyDevice(m_vkDevice, nullptr); @@ -283,22 +284,24 @@ class CompositorVkTest : public ::testing::Test { } template - std::unique_ptr createBorrowedImageInfo(const SourceOrTargetImage* image) { + const ColorBufferVkImageInfo* createImageTransitionInfo(const SourceOrTargetImage* image) { static int sImageId = 0; - auto ret = std::make_unique(); + auto ret = std::make_unique(); ret->id = sImageId++; ret->width = image->m_width; ret->height = image->m_height; ret->image = image->m_vkImage; - ret->imageCreateInfo = image->m_vkImageCreateInfo; + ret->imageCreateInfoShallow = image->m_vkImageCreateInfo; ret->imageView = image->m_vkImageView; ret->imageFormat = SourceOrTargetImage::k_format; ret->preBorrowLayout = SourceOrTargetImage::k_vkImageLayout; ret->preBorrowQueueFamilyIndex = m_compositorQueueFamilyIndex; ret->postBorrowLayout = SourceOrTargetImage::k_vkImageLayout; ret->postBorrowQueueFamilyIndex = m_compositorQueueFamilyIndex; - return ret; + const auto* ptr = ret.get(); + m_allocatedImages.push_back(std::move(ret)); + return ptr; } void checkImageFilledWith(const TargetImage* image, uint32_t expectedColor) { @@ -328,6 +331,9 @@ class CompositorVkTest : public ::testing::Test { std::shared_ptr m_compositorVkQueueLock; vk_util::YcbcrSamplerPool m_YcbcrSamplerPool; + protected: + std::vector> m_allocatedImages; + private: void createInstance() { const VkApplicationInfo appInfo = { @@ -448,8 +454,8 @@ TEST_F(CompositorVkTest, EmptyCompositionShouldDrawABlackFrame) { } for (uint32_t i = 0; i < kNumImages; i++) { - const Compositor::CompositionRequest compositionRequest = { - .target = createBorrowedImageInfo(targets[i].get()), + const CompositionRequestVk compositionRequest = { + .target = createImageTransitionInfo(targets[i].get()), .layers = {}, // Note: this is empty! }; @@ -474,11 +480,11 @@ TEST_F(CompositorVkTest, SimpleComposition) { ASSERT_NE(target, nullptr); fillImageWith(target.get(), kColorBlack); - Compositor::CompositionRequest compositionRequest = { - .target = createBorrowedImageInfo(target.get()), + CompositionRequestVk compositionRequest = { + .target = createImageTransitionInfo(target.get()), }; - compositionRequest.layers.emplace_back(Compositor::CompositionRequestLayer{ - .source = createBorrowedImageInfo(source.get()), + compositionRequest.layers.emplace_back(CompositionRequestLayerVk{ + .source = createImageTransitionInfo(source.get()), .props = { .composeMode = HWC2_COMPOSITION_DEVICE, @@ -530,11 +536,11 @@ TEST_F(CompositorVkTest, BlendPremultiplied) { ASSERT_NE(target, nullptr); fillImageWith(target.get(), kColorBlack); - Compositor::CompositionRequest compositionRequest = { - .target = createBorrowedImageInfo(target.get()), + CompositionRequestVk compositionRequest = { + .target = createImageTransitionInfo(target.get()), }; - compositionRequest.layers.emplace_back(Compositor::CompositionRequestLayer{ - .source = createBorrowedImageInfo(source.get()), + compositionRequest.layers.emplace_back(CompositionRequestLayerVk{ + .source = createImageTransitionInfo(source.get()), .props = { .composeMode = HWC2_COMPOSITION_DEVICE, @@ -585,11 +591,11 @@ TEST_F(CompositorVkTest, Crop) { ASSERT_NE(target, nullptr); fillImageWith(target.get(), kColorBlack); - Compositor::CompositionRequest compositionRequest = { - .target = createBorrowedImageInfo(target.get()), + CompositionRequestVk compositionRequest = { + .target = createImageTransitionInfo(target.get()), }; - compositionRequest.layers.emplace_back(Compositor::CompositionRequestLayer{ - .source = createBorrowedImageInfo(source.get()), + compositionRequest.layers.emplace_back(CompositionRequestLayerVk{ + .source = createImageTransitionInfo(source.get()), .props = { .composeMode = HWC2_COMPOSITION_DEVICE, @@ -636,10 +642,10 @@ TEST_F(CompositorVkTest, SolidColor) { ASSERT_NE(target, nullptr); fillImageWith(target.get(), kColorBlack); - Compositor::CompositionRequest compositionRequest = { - .target = createBorrowedImageInfo(target.get()), + CompositionRequestVk compositionRequest = { + .target = createImageTransitionInfo(target.get()), }; - compositionRequest.layers.emplace_back(Compositor::CompositionRequestLayer{ + compositionRequest.layers.emplace_back(CompositionRequestLayerVk{ .source = nullptr, .props = { @@ -682,10 +688,10 @@ TEST_F(CompositorVkTest, SolidColorBelow) { ASSERT_NE(target, nullptr); fillImageWith(target.get(), kColorBlack); - Compositor::CompositionRequest compositionRequest = { - .target = createBorrowedImageInfo(target.get()), + CompositionRequestVk compositionRequest = { + .target = createImageTransitionInfo(target.get()), }; - compositionRequest.layers.emplace_back(Compositor::CompositionRequestLayer{ + compositionRequest.layers.emplace_back(CompositionRequestLayerVk{ .source = nullptr, .props = { @@ -707,8 +713,8 @@ TEST_F(CompositorVkTest, SolidColorBelow) { }, }, }); - compositionRequest.layers.emplace_back(Compositor::CompositionRequestLayer{ - .source = createBorrowedImageInfo(source.get()), + compositionRequest.layers.emplace_back(CompositionRequestLayerVk{ + .source = createImageTransitionInfo(source.get()), .props = { .composeMode = HWC2_COMPOSITION_DEVICE, @@ -758,11 +764,11 @@ TEST_F(CompositorVkTest, SolidColorAbove) { ASSERT_NE(target, nullptr); fillImageWith(target.get(), kColorBlack); - Compositor::CompositionRequest compositionRequest = { - .target = createBorrowedImageInfo(target.get()), + CompositionRequestVk compositionRequest = { + .target = createImageTransitionInfo(target.get()), }; - compositionRequest.layers.emplace_back(Compositor::CompositionRequestLayer{ - .source = createBorrowedImageInfo(source.get()), + compositionRequest.layers.emplace_back(CompositionRequestLayerVk{ + .source = createImageTransitionInfo(source.get()), .props = { .composeMode = HWC2_COMPOSITION_DEVICE, @@ -792,7 +798,7 @@ TEST_F(CompositorVkTest, SolidColorAbove) { .transform = HWC_TRANSFORM_NONE, }, }); - compositionRequest.layers.emplace_back(Compositor::CompositionRequestLayer{ + compositionRequest.layers.emplace_back(CompositionRequestLayerVk{ .source = nullptr, .props = { @@ -829,8 +835,8 @@ TEST_F(CompositorVkTest, Transformations) { auto source = createSourceImageFromPng(GetTestDataPath("256x256_android.png")); ASSERT_NE(source, nullptr); - Compositor::CompositionRequest compositionRequest; - compositionRequest.layers.emplace_back(Compositor::CompositionRequestLayer{ + CompositionRequestVk compositionRequest; + compositionRequest.layers.emplace_back(CompositionRequestLayerVk{ .props = { .composeMode = HWC2_COMPOSITION_DEVICE, @@ -878,9 +884,9 @@ TEST_F(CompositorVkTest, Transformations) { ASSERT_NE(target, nullptr); fillImageWith(target.get(), kColorBlack); - compositionRequest.target = createBorrowedImageInfo(target.get()); + compositionRequest.target = createImageTransitionInfo(target.get()); compositionRequest.layers[0].props.transform = transform; - compositionRequest.layers[0].source = createBorrowedImageInfo(source.get()); + compositionRequest.layers[0].source = createImageTransitionInfo(source.get()); auto compositionCompleteWaitable = compositor->compose(compositionRequest); compositionCompleteWaitable.wait(); @@ -906,8 +912,8 @@ TEST_F(CompositorVkTest, MultipleTargetsComposition) { targets.emplace_back(std::move(target)); } - Compositor::CompositionRequest compositionRequest = {}; - compositionRequest.layers.emplace_back(Compositor::CompositionRequestLayer{ + CompositionRequestVk compositionRequest = {}; + compositionRequest.layers.emplace_back(CompositionRequestLayerVk{ .props = { .composeMode = HWC2_COMPOSITION_DEVICE, @@ -942,8 +948,8 @@ TEST_F(CompositorVkTest, MultipleTargetsComposition) { for (uint32_t i = 0; i < kNumCompostions; i++) { const auto& target = targets[i]; - compositionRequest.target = createBorrowedImageInfo(target.get()); - compositionRequest.layers[0].source = createBorrowedImageInfo(source.get()), + compositionRequest.target = createImageTransitionInfo(target.get()); + compositionRequest.layers[0].source = createImageTransitionInfo(source.get()), compositionRequest.layers[0].props.displayFrame.left = (i + 0) * displayFrameWidth; compositionRequest.layers[0].props.displayFrame.right = (i + 1) * displayFrameWidth; @@ -973,11 +979,11 @@ TEST_F(CompositorVkTest, MultipleLayers) { ASSERT_NE(target, nullptr); fillImageWith(target.get(), kColorBlack); - Compositor::CompositionRequest compositionRequest = { - .target = createBorrowedImageInfo(target.get()), + CompositionRequestVk compositionRequest = { + .target = createImageTransitionInfo(target.get()), }; - compositionRequest.layers.emplace_back(Compositor::CompositionRequestLayer{ - .source = createBorrowedImageInfo(source1.get()), + compositionRequest.layers.emplace_back(CompositionRequestLayerVk{ + .source = createImageTransitionInfo(source1.get()), .props = { .composeMode = HWC2_COMPOSITION_DEVICE, @@ -1007,8 +1013,8 @@ TEST_F(CompositorVkTest, MultipleLayers) { .transform = HWC_TRANSFORM_NONE, }, }); - compositionRequest.layers.emplace_back(Compositor::CompositionRequestLayer{ - .source = createBorrowedImageInfo(source2.get()), + compositionRequest.layers.emplace_back(CompositionRequestLayerVk{ + .source = createImageTransitionInfo(source2.get()), .props = { .composeMode = HWC2_COMPOSITION_DEVICE, @@ -1038,8 +1044,8 @@ TEST_F(CompositorVkTest, MultipleLayers) { .transform = HWC_TRANSFORM_ROT_90, }, }); - compositionRequest.layers.emplace_back(Compositor::CompositionRequestLayer{ - .source = createBorrowedImageInfo(source2.get()), + compositionRequest.layers.emplace_back(CompositionRequestLayerVk{ + .source = createImageTransitionInfo(source2.get()), .props = { .composeMode = HWC2_COMPOSITION_DEVICE, diff --git a/host/vulkan/device_lost_helper.h b/host/vulkan/device_lost_helper.h index f282f532f..d21188943 100644 --- a/host/vulkan/device_lost_helper.h +++ b/host/vulkan/device_lost_helper.h @@ -22,8 +22,8 @@ #include #include +#include "common/goldfish_vk_dispatch.h" #include "gfxstream/ThreadAnnotations.h" -#include "vulkan/cereal/common/goldfish_vk_dispatch.h" namespace gfxstream { namespace host { diff --git a/host/vulkan/display_surface_vk.cpp b/host/vulkan/display_surface_vk.cpp index b8ca49ff5..d9da517d2 100644 --- a/host/vulkan/display_surface_vk.cpp +++ b/host/vulkan/display_surface_vk.cpp @@ -18,7 +18,7 @@ #if defined(VK_USE_PLATFORM_XCB_KHR) #include "gfxstream/host/X11Support.h" #endif -#include "native_sub_window.h" +#include "gfxstream/host/native_sub_window.h" #include "vk_utils.h" namespace gfxstream { diff --git a/host/vulkan/display_vk.cpp b/host/vulkan/display_vk.cpp index 0489c71f4..4c4375575 100644 --- a/host/vulkan/display_vk.cpp +++ b/host/vulkan/display_vk.cpp @@ -14,16 +14,18 @@ #include "display_vk.h" +#include + #include #include #include #include +#include "color_buffer_vk.h" #include "gfxstream/common/logging.h" #include "gfxstream/host/display_operations.h" #include "gfxstream/system/System.h" -#include "vulkan/vk_enum_string_helper.h" -#include "vulkan/vk_format_utils.h" +#include "vk_format_utils.h" namespace gfxstream { namespace host { @@ -268,7 +270,7 @@ DisplayVk::PostResult DisplayVk::postImpl(const Post& postCmd) { struct ImageBorrower { ImageBorrower(const VulkanDispatch& vk, VkQueue queue, std::shared_ptr queueLock, - uint32_t usedQueueFamilyIndex, const BorrowedImageInfoVk& image, + uint32_t usedQueueFamilyIndex, const ColorBufferVkImageInfo& image, const ImageBorrowResource& acquireResource, const ImageBorrowResource& releaseResource, VkImageLayout layout) : m_vk(vk), @@ -284,8 +286,9 @@ DisplayVk::PostResult DisplayVk::postImpl(const Post& postCmd) { accessMask = VK_ACCESS_SHADER_READ_BIT; } - addNeededBarriersToUseBorrowedImage( - image, usedQueueFamilyIndex, + vk_util::addNeededBarriersToUseImage( + image.image, image.preBorrowQueueFamilyIndex, image.preBorrowLayout, + image.postBorrowQueueFamilyIndex, image.postBorrowLayout, usedQueueFamilyIndex, /*usedInitialImageLayout=*/layout, /*usedFinalImageLayout=*/layout, accessMask, &acquireQueueTransferBarriers, &acquireLayoutTransitionBarriers, &releaseLayoutTransitionBarriers, @@ -407,8 +410,8 @@ DisplayVk::PostResult DisplayVk::postImpl(const Post& postCmd) { const auto& layer = postCmd.layers[0]; if (layer.rotationDegrees == 0 && !layer.colorTransform.has_value() && hwc_rect_get_width(&layer.displayFrame) == 0 && !postCmd.colorTransform.has_value()) { - const auto* sourceImageInfoVk = static_cast(layer.info); - if (canPost(sourceImageInfoVk->imageCreateInfo)) { + const auto* sourceImageInfoVk = layer.info; + if (canPost(sourceImageInfoVk->imageCreateInfoShallow)) { useBlit = true; } } @@ -419,7 +422,7 @@ DisplayVk::PostResult DisplayVk::postImpl(const Post& postCmd) { for (size_t i = 0; i < postCmd.layers.size(); ++i) { const auto& layer = postCmd.layers[i]; - const auto* sourceImageInfoVk = static_cast(layer.info); + const auto* sourceImageInfoVk = layer.info; VkImageLayout layout = useBlit ? VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL : VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; @@ -560,7 +563,7 @@ DisplayVk::PostResult DisplayVk::postImpl(const Post& postCmd) { if (useBlit) { // Use vkCmdBlitImage to post the image (single image optimized path) const auto& layer = postCmd.layers[0]; - const auto* sourceImageInfoVk = static_cast(layer.info); + const auto* sourceImageInfoVk = layer.info; VkImageMemoryBarrier acquireSwapchainImageBarrier = { .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, .srcAccessMask = curSrcAccessMask, @@ -583,10 +586,11 @@ DisplayVk::PostResult DisplayVk::postImpl(const Post& postCmd) { .mipLevel = 0, .baseArrayLayer = 0, .layerCount = 1}, - .srcOffsets = {{0, 0, 0}, - {static_cast(sourceImageInfoVk->imageCreateInfo.extent.width), - static_cast(sourceImageInfoVk->imageCreateInfo.extent.height), - 1}}, + .srcOffsets = + {{0, 0, 0}, + {static_cast(sourceImageInfoVk->imageCreateInfoShallow.extent.width), + static_cast(sourceImageInfoVk->imageCreateInfoShallow.extent.height), + 1}}, .dstSubresource = {.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .mipLevel = 0, .baseArrayLayer = 0, @@ -595,8 +599,8 @@ DisplayVk::PostResult DisplayVk::postImpl(const Post& postCmd) { {static_cast(swapchainImageExtent.width), static_cast(swapchainImageExtent.height), 1}}, }; - VkFormat displayBufferFormat = sourceImageInfoVk->imageCreateInfo.format; - VkImageTiling displayBufferTiling = sourceImageInfoVk->imageCreateInfo.tiling; + VkFormat displayBufferFormat = sourceImageInfoVk->imageCreateInfoShallow.format; + VkImageTiling displayBufferTiling = sourceImageInfoVk->imageCreateInfoShallow.tiling; VkFilter filter = VK_FILTER_NEAREST; VkFormatFeatureFlags displayBufferFormatFeatures = @@ -663,7 +667,7 @@ DisplayVk::PostResult DisplayVk::postImpl(const Post& postCmd) { for (size_t i = 0; i < postCmd.layers.size(); ++i) { const auto& layer = postCmd.layers[i]; - const auto* sourceImageInfoVk = static_cast(layer.info); + const auto* sourceImageInfoVk = layer.info; // Strictly disable skin/mask if multi-display mode is active, regardless of image count bool isMultiDisplay = postCmd.layers.size() > 1; bool disableMask = isMultiDisplay; diff --git a/host/vulkan/display_vk.h b/host/vulkan/display_vk.h index 0ec82eb0b..3d0a6a5a1 100644 --- a/host/vulkan/display_vk.h +++ b/host/vulkan/display_vk.h @@ -27,11 +27,10 @@ #include "compositor_vk.h" #include "debug_utils_helper.h" #include "display_surface_vk.h" -#include "gfxstream/host/borrowed_image.h" #include "gfxstream/host/display.h" +#include "gfxstream/host/hwc2.h" #include "gfxstream/synchronization/Lock.h" #include "goldfish_vk_dispatch.h" -#include "host/hwc2.h" #include "swap_chain_state_vk.h" // The DisplayVk class holds the Vulkan and other states required to draw a @@ -41,6 +40,8 @@ namespace gfxstream { namespace host { namespace vk { +struct ColorBufferVkImageInfo; + class DisplayVk : public Display { public: DisplayVk(const VulkanDispatch&, VkPhysicalDevice, VkDevice, CompositorVk* compositorVk, @@ -52,7 +53,7 @@ class DisplayVk : public Display { ~DisplayVk(); struct PostLayer { - const BorrowedImageInfo* info; + const ColorBufferVkImageInfo* info; float rotationDegrees; std::optional> colorTransform; hwc_rect_t displayFrame; diff --git a/host/vulkan/display_vk_unittest.cpp b/host/vulkan/display_vk_unittest.cpp index 6fc88ccb0..1df7e84f4 100644 --- a/host/vulkan/display_vk_unittest.cpp +++ b/host/vulkan/display_vk_unittest.cpp @@ -18,11 +18,11 @@ #include "display_vk.h" -#include "borrowed_image_vk.h" -#include "gfxstream/synchronization/Lock.h" -#include "gfxstream/host/testing/SampleApplication.h" +#include "color_buffer_vk.h" #include "gfxstream/host/testing/OSWindow.h" +#include "gfxstream/host/testing/SampleApplication.h" #include "gfxstream/host/testing/VkTestUtils.h" +#include "gfxstream/synchronization/Lock.h" #include "vulkan/vulkan_dispatch.h" namespace gfxstream { @@ -82,16 +82,16 @@ class DisplayVkTest : public ::testing::Test { } } - std::unique_ptr createBorrowedImageInfo( + std::unique_ptr createImageTransitionInfo( const std::unique_ptr& texture) { static uint32_t sTextureId = 0; - auto info = std::make_unique(); + auto info = std::make_unique(); info->id = sTextureId++; info->width = texture->m_vkImageCreateInfo.extent.width; info->height = texture->m_vkImageCreateInfo.extent.height; info->image = texture->m_vkImage; - info->imageCreateInfo = texture->m_vkImageCreateInfo; + info->imageCreateInfoShallow = texture->m_vkImageCreateInfo; info->preBorrowLayout = RenderTexture::k_vkImageLayout; info->preBorrowQueueFamilyIndex = m_compositorQueueFamilyIndex; info->postBorrowLayout = RenderTexture::k_vkImageLayout; @@ -238,7 +238,7 @@ TEST_F(DisplayVkTest, PostWithoutSurfaceShouldntCrash) { m_vkCommandPool, textureWidth, textureHeight); std::vector pixels(textureWidth * textureHeight, 0); ASSERT_TRUE(texture->write(pixels)); - const auto imageInfo = createBorrowedImageInfo(texture); + const auto imageInfo = createImageTransitionInfo(texture); DisplayVk::Post postCmd; DisplayVk::PostLayer layer; layer.info = imageInfo.get(); @@ -266,7 +266,7 @@ TEST_F(DisplayVkTest, SimplePost) { ASSERT_TRUE(texture->write(pixels)); std::vector> waitForGpuFutures; for (uint32_t i = 0; i < 10; i++) { - const auto imageInfo = createBorrowedImageInfo(texture); + const auto imageInfo = createImageTransitionInfo(texture); DisplayVk::Post postCmd; DisplayVk::PostLayer layer; layer.info = imageInfo.get(); @@ -299,8 +299,8 @@ TEST_F(DisplayVkTest, PostTwoColorBuffers) { ASSERT_TRUE(greenTexture->write(greenPixels)); std::vector> waitForGpuFutures; for (uint32_t i = 0; i < 10; i++) { - const auto redImageInfo = createBorrowedImageInfo(redTexture); - const auto greenImageInfo = createBorrowedImageInfo(greenTexture); + const auto redImageInfo = createImageTransitionInfo(redTexture); + const auto greenImageInfo = createImageTransitionInfo(greenTexture); DisplayVk::Post redPostCmd; DisplayVk::PostLayer redLayer; redLayer.info = redImageInfo.get(); @@ -344,7 +344,7 @@ TEST_F(DisplayVkTest, PostWithRotation) { ASSERT_TRUE(texture->write(pixels)); std::vector> waitForGpuFutures; for (uint32_t i = 0; i < 10; i++) { - const auto imageInfo = createBorrowedImageInfo(texture); + const auto imageInfo = createImageTransitionInfo(texture); DisplayVk::Post postCmd; DisplayVk::PostLayer layer; layer.info = imageInfo.get(); @@ -379,7 +379,7 @@ TEST_F(DisplayVkTest, PostWithColorTransform) { ASSERT_TRUE(texture->write(pixels)); std::vector> waitForGpuFutures; for (uint32_t i = 0; i < 10; i++) { - const auto imageInfo = createBorrowedImageInfo(texture); + const auto imageInfo = createImageTransitionInfo(texture); DisplayVk::Post postCmd; DisplayVk::PostLayer layer; layer.info = imageInfo.get(); @@ -414,8 +414,8 @@ TEST_F(DisplayVkTest, PostMultiDisplayComposition) { std::vector> waitForGpuFutures; for (uint32_t i = 0; i < 10; i++) { - const auto redImageInfo = createBorrowedImageInfo(redTexture); - const auto greenImageInfo = createBorrowedImageInfo(greenTexture); + const auto redImageInfo = createImageTransitionInfo(redTexture); + const auto greenImageInfo = createImageTransitionInfo(greenTexture); DisplayVk::Post postCmd; // Combined frame size (side-by-side) diff --git a/host/vulkan/emulated_textures/BUILD.bazel b/host/vulkan/emulated_textures/BUILD.bazel index 69a449fc1..c6fc03635 100644 --- a/host/vulkan/emulated_textures/BUILD.bazel +++ b/host/vulkan/emulated_textures/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -21,6 +21,7 @@ cc_library( ], copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, + linkopts = GFXSTREAM_HOST_LINKOPTS, textual_hdrs = glob([ "**/*.inl", ]), @@ -28,7 +29,6 @@ cc_library( deps = [ "//common/base:gfxstream_common_base", "//common/logging:gfxstream_common_logging", - "//host:gfxstream_host_headers", "//host/compressed_textures:gfxstream_host_compressed_textures", "//host/vulkan:gfxstream_vulkan_server_headers", "//host/vulkan/cereal:gfxstream_vulkan_cereal", diff --git a/host/vulkan/emulated_textures/astc_texture.cpp b/host/vulkan/emulated_textures/astc_texture.cpp index 70d0d0f27..41bbbf47a 100644 --- a/host/vulkan/emulated_textures/astc_texture.cpp +++ b/host/vulkan/emulated_textures/astc_texture.cpp @@ -21,7 +21,7 @@ #include #include "gfxstream/common/logging.h" -#include "vulkan/vk_utils.h" +#include "vk_utils.h" namespace gfxstream { namespace host { diff --git a/host/vulkan/emulated_textures/astc_texture.h b/host/vulkan/emulated_textures/astc_texture.h index 04ca46a20..18f6d136a 100644 --- a/host/vulkan/emulated_textures/astc_texture.h +++ b/host/vulkan/emulated_textures/astc_texture.h @@ -13,10 +13,11 @@ // limitations under the License. #pragma once +#include + #include "gfxstream/host/astc_cpu_decompressor.h" -#include "vulkan/vk_decoder_context.h" #include "goldfish_vk_dispatch.h" -#include "vulkan/vulkan.h" +#include "vk_decoder_context.h" namespace gfxstream { namespace host { diff --git a/host/vulkan/emulated_textures/compressed_image_info.cpp b/host/vulkan/emulated_textures/compressed_image_info.cpp index cd0913078..add9dd740 100644 --- a/host/vulkan/emulated_textures/compressed_image_info.cpp +++ b/host/vulkan/emulated_textures/compressed_image_info.cpp @@ -14,12 +14,12 @@ #include "compressed_image_info.h" +#include + +#include "emulated_textures/shaders/decompression_shaders.h" #include "gfxstream/ArraySize.h" #include "gfxstream/common/logging.h" -#include "vulkan/vk_format_utils.h" -#include "vulkan/emulated_textures/shaders/decompression_shaders.h" -#include "vulkan/vk_format_utils.h" -#include "vulkan/vk_enum_string_helper.h" +#include "vk_format_utils.h" namespace gfxstream { namespace host { diff --git a/host/vulkan/emulated_textures/compressed_image_info.h b/host/vulkan/emulated_textures/compressed_image_info.h index 4536fdb26..9db6cab36 100644 --- a/host/vulkan/emulated_textures/compressed_image_info.h +++ b/host/vulkan/emulated_textures/compressed_image_info.h @@ -14,15 +14,16 @@ #pragma once +#include + #include #include #include #include -#include "vulkan/emulated_textures/astc_texture.h" -#include "vulkan/emulated_textures/gpu_decompression_pipeline.h" +#include "emulated_textures/astc_texture.h" +#include "emulated_textures/gpu_decompression_pipeline.h" #include "goldfish_vk_dispatch.h" -#include "vulkan/vulkan.h" namespace gfxstream { namespace host { diff --git a/host/vulkan/emulated_textures/gpu_decompression_pipeline.cpp b/host/vulkan/emulated_textures/gpu_decompression_pipeline.cpp index dffd26ce6..e5e426e0a 100644 --- a/host/vulkan/emulated_textures/gpu_decompression_pipeline.cpp +++ b/host/vulkan/emulated_textures/gpu_decompression_pipeline.cpp @@ -14,15 +14,15 @@ #include "gpu_decompression_pipeline.h" +#include + +#include "emulated_textures/shaders/decompression_shaders.h" #include "gfxstream/common/logging.h" -#include "vulkan/vk_format_utils.h" -#include "vulkan/emulated_textures/shaders/decompression_shaders.h" -#include "vulkan/vk_enum_string_helper.h" +#include "vk_format_utils.h" namespace gfxstream { namespace host { namespace vk { - namespace { // Which GPU decoder we use for ASTC textures. diff --git a/host/vulkan/meson.build b/host/vulkan/meson.build index 6bc04c3a6..2ea154a65 100644 --- a/host/vulkan/meson.build +++ b/host/vulkan/meson.build @@ -9,7 +9,6 @@ subdir('cereal') subdir('emulated_textures') files_lib_vulkan_server = files( - 'borrowed_image_vk.cpp', 'buffer_vk.cpp', 'color_buffer_vk.cpp', 'compositor_vk.cpp', @@ -74,6 +73,7 @@ lib_vulkan_server = static_library( inc_cereal_common, inc_cereal, inc_common_base, + inc_common_logging, inc_common_utils, inc_gl_openglesdispatch, inc_gl_server, @@ -85,9 +85,8 @@ lib_vulkan_server = static_library( inc_host_include, inc_host_iostream, inc_host_library, - inc_common_logging, + inc_host_native_window, inc_host_renderdoc, - inc_host_snapshot, inc_host_tracing, inc_include, inc_opengl_headers, @@ -105,6 +104,7 @@ lib_vulkan_server = static_library( lib_host_compressed_textures, lib_host_features, lib_host_library, + lib_host_native_window, lib_host_tracing, lib_vulkan_cereal, ], diff --git a/host/vulkan/post_worker_vk.cpp b/host/vulkan/post_worker_vk.cpp index 907409568..4cd71d147 100644 --- a/host/vulkan/post_worker_vk.cpp +++ b/host/vulkan/post_worker_vk.cpp @@ -15,12 +15,13 @@ */ #include "post_worker_vk.h" -#include "host/frame_buffer.h" +#include "color_buffer_vk.h" +#include "display_vk.h" +#include "gfxstream/common/logging.h" #include "gfxstream/host/display_operations.h" +#include "gfxstream/host/global_state.h" #include "gfxstream/host/renderer_operations.h" #include "gfxstream/host/window_operations.h" -#include "gfxstream/common/logging.h" -#include "vulkan/display_vk.h" namespace gfxstream { namespace host { @@ -42,11 +43,12 @@ hwc_transform_t getTransformFromRotation(int rotation) { } // namespace -PostWorkerVk::PostWorkerVk(FrameBuffer* fb, Compositor* compositor, vk::DisplayVk* displayVk) - : PostWorker(false, fb, compositor), m_displayVk(displayVk) {} +PostWorkerVk::PostWorkerVk(gfxstream::host::GlobalState* globalState, Compositor* compositor, + vk::DisplayVk* displayVk) + : PostWorker(false, globalState, compositor), m_displayVk(displayVk) {} -std::shared_future PostWorkerVk::postImpl(ColorBuffer* cb, - const std::optional>& colorTransform) { +std::shared_future PostWorkerVk::postImpl( + IColorBuffer* cb, const std::optional>& colorTransform) { std::shared_future completedFuture = std::async(std::launch::deferred, [] {}).share(); completedFuture.wait(); @@ -54,13 +56,15 @@ std::shared_future PostWorkerVk::postImpl(ColorBuffer* cb, GFXSTREAM_FATAL("PostWorker missing DisplayVk."); } - std::vector> borrowedImages; + std::vector> borrowedImages; DisplayVk::Post postCmd; - auto addPostImage = [&](ColorBuffer* colorBuffer, int32_t x, int32_t y, int32_t w, int32_t h, + auto addPostImage = [&](IColorBuffer* colorBuffer, int32_t x, int32_t y, int32_t w, int32_t h, float rotation, const std::optional>& transform = std::nullopt) { - auto info = mFb->borrowColorBufferForDisplay(colorBuffer->getHndl()); + colorBuffer->invalidateForBackend(Backend::VK); + auto cbVk = colorBuffer->getColorBufferVk(); + auto info = cbVk ? cbVk->prepareForDisplay() : nullptr; if (!info) return; DisplayVk::PostLayer layer; @@ -83,12 +87,12 @@ std::shared_future PostWorkerVk::postImpl(ColorBuffer* cb, if (pixel_fold) { #ifdef CONFIG_AEMU if (!get_gfxstream_should_skip_draw()) { - const float dpr = mFb->getDpr(); - const float px = mFb->getPx(); - const float py = mFb->getPy(); - const int windowWidth = mFb->windowWidth(); - const int windowHeight = mFb->windowHeight(); - const float zRot = static_cast(mFb->getZrot()); + const float dpr = m_globalState->getDpr(); + const float px = m_globalState->getPx(); + const float py = m_globalState->getPy(); + const int windowWidth = m_globalState->windowWidth(); + const int windowHeight = m_globalState->windowHeight(); + const float zRot = static_cast(m_globalState->getZrot()); // Calculate "excess" space (difference between viewport and content size) // m_viewportWidth/Height are updated in viewportImpl @@ -127,7 +131,8 @@ std::shared_future PostWorkerVk::postImpl(ColorBuffer* cb, currentDisplayId, currentDisplayColorBufferHandle); } // Main window post - addPostImage(cb, 0, 0, 0, 0, static_cast(mFb->getZrot()), colorTransform); + addPostImage(cb, 0, 0, 0, 0, static_cast(m_globalState->getZrot()), + colorTransform); } else { uint32_t combinedDisplayW = 0; uint32_t combinedDisplayH = 0; @@ -154,16 +159,16 @@ std::shared_future PostWorkerVk::postImpl(ColorBuffer* cb, continue; } - ColorBuffer* currentCb = + IColorBuffer* currentCb = currentDisplayId == 0 ? cb - : mFb->findColorBuffer(currentDisplayColorBufferHandle).get(); + : m_globalState->findColorBuffer(currentDisplayColorBufferHandle).get(); if (!currentCb) { continue; } - float rotation = static_cast(mFb->getZrot()); - const auto transform = getTransformFromRotation(mFb->getZrot()); + float rotation = static_cast(m_globalState->getZrot()); + const auto transform = getTransformFromRotation(m_globalState->getZrot()); if (transform == HWC_TRANSFORM_ROT_90 || transform == HWC_TRANSFORM_ROT_270) { std::swap(currentDisplayW, currentDisplayH); } @@ -174,10 +179,10 @@ std::shared_future PostWorkerVk::postImpl(ColorBuffer* cb, } else if (get_gfxstream_window_operations().is_folded()) { // TODO: Implement fold logic if needed (similar to GL) // For now simple post - addPostImage(cb, 0, 0, 0, 0, static_cast(mFb->getZrot()), colorTransform); + addPostImage(cb, 0, 0, 0, 0, static_cast(m_globalState->getZrot()), colorTransform); } else { // Simple case: single display, no special mode - addPostImage(cb, 0, 0, 0, 0, static_cast(mFb->getZrot()), colorTransform); + addPostImage(cb, 0, 0, 0, 0, static_cast(m_globalState->getZrot()), colorTransform); } constexpr const int kMaxPostRetries = 2; @@ -193,7 +198,7 @@ std::shared_future PostWorkerVk::postImpl(ColorBuffer* cb, } void PostWorkerVk::viewportImpl(int width, int height) { - const float dpr = mFb->getDpr(); + const float dpr = m_globalState->getDpr(); m_viewportWidth = width * dpr; m_viewportHeight = height * dpr; } diff --git a/host/vulkan/post_worker_vk.h b/host/vulkan/post_worker_vk.h index 9ca13318c..8a8c7f6de 100644 --- a/host/vulkan/post_worker_vk.h +++ b/host/vulkan/post_worker_vk.h @@ -16,11 +16,11 @@ #pragma once #include -#include #include +#include #include "gfxstream/host/display_surface_user.h" -#include "host/post_worker.h" +#include "gfxstream/host/post_worker.h" namespace gfxstream { namespace host { @@ -30,11 +30,12 @@ class DisplayVk; class PostWorkerVk : public PostWorker { public: - PostWorkerVk(FrameBuffer* fb, Compositor* compositor, vk::DisplayVk* displayGl); + PostWorkerVk(gfxstream::host::GlobalState* globalState, Compositor* compositor, + vk::DisplayVk* displayGl); protected: std::shared_future postImpl( - ColorBuffer* cb, const std::optional>& colorTransform) override; + IColorBuffer* cb, const std::optional>& colorTransform) override; void viewportImpl(int width, int height) override; void clearImpl() override; void exitImpl() override; diff --git a/host/vulkan/swap_chain_state_vk.cpp b/host/vulkan/swap_chain_state_vk.cpp index ac7592e6c..897d6e678 100644 --- a/host/vulkan/swap_chain_state_vk.cpp +++ b/host/vulkan/swap_chain_state_vk.cpp @@ -14,12 +14,13 @@ #include "swap_chain_state_vk.h" +#include + #include #include #include "gfxstream/common/logging.h" -#include "vulkan/vk_enum_string_helper.h" -#include "vulkan/vk_utils.h" +#include "vk_utils.h" namespace gfxstream { namespace host { diff --git a/host/vulkan/vk_android_native_buffer_operations.cpp b/host/vulkan/vk_android_native_buffer_operations.cpp index daf0040cf..faca8879b 100644 --- a/host/vulkan/vk_android_native_buffer_operations.cpp +++ b/host/vulkan/vk_android_native_buffer_operations.cpp @@ -18,8 +18,7 @@ #include "cereal/common/goldfish_vk_deepcopy.h" #include "cereal/common/goldfish_vk_extension_structs.h" -#include "frame_buffer.h" -#include "gfxstream/host/backend_callbacks.h" +#include "gfxstream/host/global_state.h" #include "gfxstream/host/tracing.h" #include "goldfish_vk_private_defs.h" #include "gralloc_defs.h" @@ -674,8 +673,7 @@ VkResult AndroidNativeBufferInfo::on_vkQueueSignalReleaseImageANDROID( GFXSTREAM_TRACE_EVENT(GFXSTREAM_TRACE_DEFAULT_CATEGORY, "vkQSRI syncImageToColorBuffer()", GFXSTREAM_TRACE_FLOW(traceId)); - auto fb = FrameBuffer::getFB(); - fb->lock(); + emu->getGlobalState()->lockGlobalState(); // Implicitly synchronized *pNativeFenceFd = -1; @@ -849,13 +847,13 @@ VkResult AndroidNativeBufferInfo::on_vkQueueSignalReleaseImageANDROID( VK_ANB_DEBUG_OBJ(this, "wait callback: wait for fence %p...(done)", qsriFence); mQsriWaitFencePool->returnFence(qsriFence); }; - fb->unlock(); + emu->getGlobalState()->unlockGlobalState(); if (mUseVulkanNativeImage) { VK_ANB_DEBUG_OBJ(this, "using native image, so use sync thread to wait"); // Queue wait to sync thread with completion callback // Pass anbInfo by value to get a ref - auto waitable = emu->getCallbacks().scheduleAsyncWork( + auto waitable = emu->getGlobalState()->scheduleAsyncWork( [waitForQsriFenceTask = std::move(waitForQsriFenceTask), this]() mutable { waitForQsriFenceTask(); mQsriTimeline->signalNextPresentAndPoll(); @@ -880,7 +878,7 @@ VkResult AndroidNativeBufferInfo::on_vkQueueSignalReleaseImageANDROID( string_VkFormat(mVkFormat), mVkFormat); } else { const size_t bytesSize = bytesPerPixel * mExtent.width * mExtent.height; - emu->getCallbacks().flushColorBufferFromBytes(mColorBufferHandle, bytes, bytesSize); + emu->getGlobalState()->flushColorBufferFromBytes(mColorBufferHandle, bytes, bytesSize); } mQsriTimeline->signalNextPresentAndPoll(); diff --git a/host/vulkan/vk_android_native_buffer_operations.h b/host/vulkan/vk_android_native_buffer_operations.h index 889a386ef..7848f5591 100644 --- a/host/vulkan/vk_android_native_buffer_operations.h +++ b/host/vulkan/vk_android_native_buffer_operations.h @@ -26,7 +26,6 @@ #include "gfxstream/AsyncResult.h" #include "gfxstream/BumpPool.h" #include "gfxstream/ThreadAnnotations.h" -#include "gfxstream/host/backend_callbacks.h" #include "gfxstream/synchronization/ConditionVariable.h" #include "gfxstream/synchronization/Lock.h" #include "goldfish_vk_private_defs.h" diff --git a/host/vulkan/vk_common_operations.cpp b/host/vulkan/vk_common_operations.cpp index a88948fce..4b0cfa0f7 100644 --- a/host/vulkan/vk_common_operations.cpp +++ b/host/vulkan/vk_common_operations.cpp @@ -769,9 +769,8 @@ int VkEmulation::getSelectedGpuIndex( return selectedGpuIndex; } -/*static*/ std::unique_ptr VkEmulation::create(VulkanDispatch* gvk, - gfxstream::host::BackendCallbacks callbacks, + gfxstream::host::GlobalState* globalState, const gfxstream::host::FeatureSet& features) { if (!vkDispatchValid(gvk)) { GFXSTREAM_ERROR("Dispatch is invalid."); @@ -782,7 +781,7 @@ std::unique_ptr VkEmulation::create(VulkanDispatch* gvk, std::lock_guard lock(emulation->mMutex); - emulation->mCallbacks = callbacks; + emulation->m_globalState = globalState; emulation->mGvk = gvk; emulation->setFeatures(features); @@ -1914,7 +1913,7 @@ void VkEmulation::setFeatures(const gfxstream::host::FeatureSet& features) { #endif } -const gfxstream::host::BackendCallbacks& VkEmulation::getCallbacks() const { return mCallbacks; } +gfxstream::host::GlobalState* VkEmulation::getGlobalState() const { return m_globalState; } AstcEmulationMode VkEmulation::getAstcLdrEmulationMode() const { return mAstcLdrEmulationMode; } @@ -3029,11 +3028,12 @@ bool VkEmulation::createVkColorBufferLocked(uint32_t width, uint32_t height, // Requesting invalid texture sizes can crash some drivers, early out to gracefully handle // the errors and avoid total emulator crash. - if (width > mDeviceInfo.physdevProps.limits.maxFramebufferWidth || + if (width == 0 || width > mDeviceInfo.physdevProps.limits.maxFramebufferWidth || height == 0 || height > mDeviceInfo.physdevProps.limits.maxFramebufferHeight) { GFXSTREAM_ERROR( - "%s: Cannot create color buffer(%u) with size '%u x %u', driver limits: '%u x %u'", - __func__, colorBufferHandle, width, height, + "%s: Cannot create color buffer(%u) with size '%u x %u' and format '%s', driver " + "limits: '%u x %u'", + __func__, colorBufferHandle, width, height, ToString(format).c_str(), mDeviceInfo.physdevProps.limits.maxFramebufferWidth, mDeviceInfo.physdevProps.limits.maxFramebufferHeight); return false; @@ -3784,7 +3784,7 @@ bool VkEmulation::readColorBufferPixelsScaledGpu(uint32_t colorBufferHandle, int // Check if we need to stage to GPU const int outBpp = (pixelsFormat == GfxstreamFormat::R8G8B8_UNORM) ? 3 : 4; - const uint64_t outPixelsSize = outBpp * pixelsWidth * pixelsHeight; + const uint64_t outPixelsSize = (uint64_t)outBpp * (uint64_t)pixelsWidth * (uint64_t)pixelsHeight; const int readbackBpp = 4; int readbackWidth = sourceCbInfo->width; int readbackHeight = sourceCbInfo->height; @@ -5124,7 +5124,7 @@ void VkEmulation::releaseColorBufferForGuestUse(uint32_t colorBufferHandle) { VK_CHECK(vk->vkWaitForFences(mDevice, 1, &fence, VK_TRUE, ANB_MAX_WAIT_NS)); } -std::unique_ptr VkEmulation::borrowColorBufferForComposition( +std::unique_ptr VkEmulation::prepareColorBufferForComposition( uint32_t colorBufferHandle, bool colorBufferIsTarget) { std::lock_guard lock(mMutex); @@ -5134,13 +5134,13 @@ std::unique_ptr VkEmulation::borrowColorBufferForCompositio return nullptr; } - auto compositorInfo = std::make_unique(); + auto compositorInfo = std::make_unique(); compositorInfo->id = colorBufferInfo->handle; compositorInfo->width = colorBufferInfo->imageCreateInfoShallow.extent.width; compositorInfo->height = colorBufferInfo->imageCreateInfoShallow.extent.height; compositorInfo->image = colorBufferInfo->image; compositorInfo->imageView = colorBufferInfo->imageView; - compositorInfo->imageCreateInfo = colorBufferInfo->imageCreateInfoShallow; + compositorInfo->imageCreateInfoShallow = colorBufferInfo->imageCreateInfoShallow; compositorInfo->imageFormat = colorBufferInfo->format; compositorInfo->preBorrowLayout = colorBufferInfo->currentLayout; compositorInfo->preBorrowQueueFamilyIndex = colorBufferInfo->currentQueueFamilyIndex; @@ -5166,7 +5166,7 @@ std::unique_ptr VkEmulation::borrowColorBufferForCompositio return compositorInfo; } -std::unique_ptr VkEmulation::borrowColorBufferForDisplay( +std::unique_ptr VkEmulation::prepareColorBufferForDisplay( uint32_t colorBufferHandle) { std::lock_guard lock(mMutex); @@ -5176,13 +5176,13 @@ std::unique_ptr VkEmulation::borrowColorBufferForDisplay( return nullptr; } - auto compositorInfo = std::make_unique(); + auto compositorInfo = std::make_unique(); compositorInfo->id = colorBufferInfo->handle; compositorInfo->width = colorBufferInfo->imageCreateInfoShallow.extent.width; compositorInfo->height = colorBufferInfo->imageCreateInfoShallow.extent.height; compositorInfo->image = colorBufferInfo->image; compositorInfo->imageView = colorBufferInfo->imageView; - compositorInfo->imageCreateInfo = colorBufferInfo->imageCreateInfoShallow; + compositorInfo->imageCreateInfoShallow = colorBufferInfo->imageCreateInfoShallow; compositorInfo->imageFormat = colorBufferInfo->format; compositorInfo->preBorrowLayout = colorBufferInfo->currentLayout; compositorInfo->preBorrowQueueFamilyIndex = mQueueFamilyIndex; @@ -5198,6 +5198,18 @@ std::unique_ptr VkEmulation::borrowColorBufferForDisplay( return compositorInfo; } +void VkEmulation::updateColorBufferLayoutAndQueue(uint32_t colorBufferHandle, VkImageLayout layout, + uint32_t queueFamilyIndex) { + std::lock_guard lock(mMutex); + auto colorBufferInfo = gfxstream::base::find(mColorBuffers, colorBufferHandle); + if (!colorBufferInfo) { + GFXSTREAM_ERROR("Invalid ColorBuffer handle %d.", static_cast(colorBufferHandle)); + return; + } + colorBufferInfo->currentLayout = layout; + colorBufferInfo->currentQueueFamilyIndex = queueFamilyIndex; +} + std::optional VkEmulation::findRepresentativeColorBufferMemoryTypeIndexLocked() { constexpr const uint32_t kArbitraryWidth = 64; diff --git a/host/vulkan/vk_common_operations.h b/host/vulkan/vk_common_operations.h index 8ba6a0e1d..0d5e5a9d8 100644 --- a/host/vulkan/vk_common_operations.h +++ b/host/vulkan/vk_common_operations.h @@ -23,24 +23,24 @@ #include #include -#include "borrowed_image_vk.h" +#include "color_buffer_vk.h" #include "compositor_vk.h" #include "debug_utils_helper.h" #include "device_lost_helper.h" #include "display_vk.h" #include "external_memory.h" -#include "gfxstream/host/backend_callbacks.h" +#include "gfxstream/Optional.h" +#include "gfxstream/ThreadAnnotations.h" +#include "gfxstream/host/GfxApiLogger.h" +#include "gfxstream/host/RenderDoc.h" #include "gfxstream/host/external_object_manager.h" #include "gfxstream/host/features.h" +#include "gfxstream/host/framework_formats.h" #include "gfxstream/host/gfxstream_format.h" -#include "gfxstream/host/GfxApiLogger.h" -#include "gfxstream/host/RenderDoc.h" +#include "gfxstream/host/global_state.h" #include "gfxstream/host/vk_enums.h" #include "gfxstream/memory/UdmabufCreator.h" -#include "gfxstream/Optional.h" -#include "gfxstream/ThreadAnnotations.h" #include "goldfish_vk_private_defs.h" -#include "host/framework_formats.h" #include "render-utils/Renderer.h" #include "vk_format_support.h" #include "vk_utils.h" @@ -96,7 +96,7 @@ class VkEmulation { ~VkEmulation(); static std::unique_ptr create(VulkanDispatch* vk, - gfxstream::host::BackendCallbacks callbacks, + gfxstream::host::GlobalState* globalState, const gfxstream::host::FeatureSet& features); struct Features { @@ -171,7 +171,7 @@ class VkEmulation { const gfxstream::host::FeatureSet& getFeatures() const; - const gfxstream::host::BackendCallbacks& getCallbacks() const; + gfxstream::host::GlobalState* getGlobalState() const; AstcEmulationMode getAstcLdrEmulationMode() const; @@ -451,9 +451,12 @@ class VkEmulation { void releaseColorBufferForGuestUse(uint32_t colorBufferHandle); - std::unique_ptr borrowColorBufferForComposition(uint32_t colorBufferHandle, - bool colorBufferIsTarget); - std::unique_ptr borrowColorBufferForDisplay(uint32_t colorBufferHandle); + std::unique_ptr prepareColorBufferForComposition( + uint32_t colorBufferHandle, bool colorBufferIsTarget); + std::unique_ptr prepareColorBufferForDisplay( + uint32_t colorBufferHandle); + void updateColorBufferLayoutAndQueue(uint32_t colorBufferHandle, VkImageLayout layout, + uint32_t queueFamilyIndex); void applyApiVersionLimits(uint32_t& apiVersion) const { if (apiVersion > mGuestVulkanMaxApiVersion) { @@ -569,7 +572,7 @@ class VkEmulation { std::mutex mMutex; - gfxstream::host::BackendCallbacks mCallbacks; + gfxstream::host::GlobalState* m_globalState = nullptr; gfxstream::host::FeatureSet mFeatures; diff --git a/host/vulkan/vk_decoder.cpp b/host/vulkan/vk_decoder.cpp index 3174d3256..9728139e8 100644 --- a/host/vulkan/vk_decoder.cpp +++ b/host/vulkan/vk_decoder.cpp @@ -38,7 +38,6 @@ #include "common/goldfish_vk_marshaling.h" #include "common/goldfish_vk_reserved_marshaling.h" #include "common/goldfish_vk_transform.h" -#include "frame_buffer.h" #include "gfxstream/BumpPool.h" #include "gfxstream/common/logging.h" #include "gfxstream/host/iostream.h" diff --git a/host/vulkan/vk_decoder_global_state.cpp b/host/vulkan/vk_decoder_global_state.cpp index 3161cf00b..68a519714 100644 --- a/host/vulkan/vk_decoder_global_state.cpp +++ b/host/vulkan/vk_decoder_global_state.cpp @@ -13,15 +13,6 @@ // limitations under the License. #include "vk_decoder_global_state.h" -#include -#include -#include -#include -#include -#include -#include -#include - #ifndef _WIN32 #include #endif @@ -35,43 +26,51 @@ #include // for MoltenVK portability extensions #endif +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + #include "common/goldfish_vk_deepcopy.h" #include "common/goldfish_vk_dispatch.h" #include "common/goldfish_vk_marshaling.h" #include "common/goldfish_vk_reserved_marshaling.h" +#include "emulated_textures/astc_texture.h" +#include "emulated_textures/compressed_image_info.h" +#include "emulated_textures/gpu_decompression_pipeline.h" +#include "gfxstream/Macros.h" #include "gfxstream/common/logging.h" #include "gfxstream/containers/Lookup.h" +#include "gfxstream/host/RenderDoc.h" #include "gfxstream/host/address_space_operations.h" #include "gfxstream/host/astc_cpu_decompressor.h" #include "gfxstream/host/graphics_driver_lock.h" -#include "gfxstream/host/RenderDoc.h" #include "gfxstream/host/tracing.h" #include "gfxstream/host/vm_operations.h" -#include "gfxstream/Macros.h" #include "gfxstream/strings.h" -#include "host/frame_buffer.h" -#include "render_thread_info_vk.h" #include "render-utils/stream.h" +#include "render_thread_info_vk.h" #include "trivial_stream.h" #include "vk_android_native_buffer_operations.h" #include "vk_common_operations.h" #include "vk_decoder_context.h" #include "vk_decoder_internal_structs.h" -#include "vk_decoder_snapshot_utils.h" #include "vk_decoder_snapshot.h" +#include "vk_decoder_snapshot_utils.h" #include "vk_emulated_physical_device_memory.h" #include "vk_emulated_physical_device_queue.h" +#include "vk_format_utils.h" #include "vk_utils.h" #include "vulkan_boxed_handles.h" #include "vulkan_dispatch.h" #include "vulkan_stream.h" -#include "vulkan/emulated_textures/astc_texture.h" -#include "vulkan/emulated_textures/compressed_image_info.h" -#include "vulkan/emulated_textures/gpu_decompression_pipeline.h" -#include "vulkan/vk_enum_string_helper.h" -#include "vulkan/vk_format_utils.h" -#include "vulkan/vulkan_core.h" - // Verbose logging only when ANDROID_EMU_VK_LOG_CALLS is set #define LOG_CALLS_VERBOSE(fmt, ...) \ @@ -446,7 +445,7 @@ class VkDecoderGlobalState::Impl { stateBlock->deviceDispatch->vkDestroyCommandPool(stateBlock->device, stateBlock->commandPool, nullptr); } - void save(gfxstream::Stream* stream) { + bool save(gfxstream::Stream* stream) { GFXSTREAM_DEBUG("VulkanSnapshots save (begin)"); std::lock_guard lock(mMutex); @@ -534,7 +533,10 @@ class VkDecoderGlobalState::Impl { StateBlock stateBlock = createSnapshotStateBlock(imageInfo.device); // TODO(b/294277842): make sure the queue is empty before using. - saveImageContent(stream, &stateBlock, unboxedImage, &imageInfo); + if (!saveImageContent(stream, &stateBlock, unboxedImage, &imageInfo)) { + releaseSnapshotStateBlock(&stateBlock); + return false; + } releaseSnapshotStateBlock(&stateBlock); } @@ -560,7 +562,10 @@ class VkDecoderGlobalState::Impl { StateBlock stateBlock = createSnapshotStateBlock(bufferInfo.device); // TODO(b/294277842): make sure the queue is empty before using. - saveBufferContent(stream, &stateBlock, unboxedBuffer, &bufferInfo); + if (!saveBufferContent(stream, &stateBlock, unboxedBuffer, &bufferInfo)) { + releaseSnapshotStateBlock(&stateBlock); + return false; + } releaseSnapshotStateBlock(&stateBlock); } @@ -705,12 +710,16 @@ class VkDecoderGlobalState::Impl { unboxed_to_boxed_non_dispatchable_VkBufferView(entry.bufferView); stream->write(&bufferView, sizeof(bufferView)); } break; - case DescriptorSetInfo::DescriptorWriteType::InlineUniformBlock: + case DescriptorSetInfo::DescriptorWriteType::InlineUniformBlock: { + uint32_t dataSize = entry.inlineUniformBlockBuffer.size(); + stream->putBe32(dataSize); + stream->write(entry.inlineUniformBlockBuffer.data(), dataSize); + } break; case DescriptorSetInfo::DescriptorWriteType::AccelerationStructure: - // TODO - GFXSTREAM_FATAL("Encountered pending inline uniform block or acceleration " - "structure desc write, abort (NYI)"); - break; + GFXSTREAM_ERROR( + "Encountered pending acceleration " + "structure desc write, abort (NYI)"); + return false; default: break; } @@ -743,9 +752,10 @@ class VkDecoderGlobalState::Impl { mSnapshotState = SnapshotState::Normal; GFXSTREAM_DEBUG("VulkanSnapshots save (end)"); + return true; } - void load(gfxstream::Stream* stream, GfxApiLogger& gfxLogger) { + bool load(gfxstream::Stream* stream, GfxApiLogger& gfxLogger) { // assume that we already destroyed all instances // from FrameBuffer's onLoad method. GFXSTREAM_DEBUG("VulkanSnapshots load (begin)"); @@ -804,8 +814,13 @@ class VkDecoderGlobalState::Impl { .processName = nullptr, .gfxApiLogger = &gfxLogger, }; - decoderForLoading.decode(decoderReplayBuffer.data(), decoderReplayBuffer.size(), - &trivialStream, resources.get(), context); + size_t consumed = decoderForLoading.decode(decoderReplayBuffer.data(), decoderReplayBuffer.size(), + &trivialStream, resources.get(), context); + if (consumed != decoderReplayBuffer.size()) { + GFXSTREAM_ERROR("Failed to completely decode snapshot replay buffer. Consumed %zu of %zu bytes", + consumed, decoderReplayBuffer.size()); + return false; + } } { @@ -819,11 +834,13 @@ class VkDecoderGlobalState::Impl { VkDeviceMemory unboxedMemory = unbox_VkDeviceMemory(boxedMemory); auto it = mMemoryInfo.find(unboxedMemory); if (it == mMemoryInfo.end()) { - GFXSTREAM_FATAL("Snapshot load failure: cannot find memory handle for VkDeviceMemory:%p", boxedMemory); + GFXSTREAM_ERROR("Snapshot load failure: cannot find memory handle for VkDeviceMemory:%p", boxedMemory); + return false; } VkDeviceSize size = stream->getBe64(); if (size != it->second.size || !it->second.ptr) { - GFXSTREAM_FATAL("Snapshot load failure: memory size does not match for VkDeviceMemory:%p", boxedMemory); + GFXSTREAM_ERROR("Snapshot load failure: memory size does not match for VkDeviceMemory:%p", boxedMemory); + return false; } stream->read(it->second.ptr, size); } @@ -862,7 +879,10 @@ class VkDecoderGlobalState::Impl { imageInfo.layout = static_cast(stream->getBe32()); StateBlock stateBlock = createSnapshotStateBlock(imageInfo.device); // TODO(b/294277842): make sure the queue is empty before using. - loadImageContent(stream, &stateBlock, unboxedImage, &imageInfo); + if (!loadImageContent(stream, &stateBlock, unboxedImage, &imageInfo)) { + releaseSnapshotStateBlock(&stateBlock); + return false; + } releaseSnapshotStateBlock(&stateBlock); } @@ -883,7 +903,10 @@ class VkDecoderGlobalState::Impl { // TODO: add a special case for host mapped memory StateBlock stateBlock = createSnapshotStateBlock(bufferInfo.device); // TODO(b/294277842): make sure the queue is empty before using. - loadBufferContent(stream, &stateBlock, unboxedBuffer, &bufferInfo); + if (!loadBufferContent(stream, &stateBlock, unboxedBuffer, &bufferInfo)) { + releaseSnapshotStateBlock(&stateBlock); + return false; + } releaseSnapshotStateBlock(&stateBlock); } @@ -922,6 +945,9 @@ class VkDecoderGlobalState::Impl { std::vector> tmpImageInfos; std::vector> tmpBufferInfos; std::vector> tmpBufferViews; + std::vector> + tmpInlineUniformBlocks; + std::vector> tmpInlineUniformBlockBuffers; for (uint64_t poolId : allpoolIds) { bool allocated = stream->getByte(); @@ -978,12 +1004,38 @@ class VkDecoderGlobalState::Impl { stream->read(&bufferView, sizeof(bufferView)); bufferView = unbox_VkBufferView(bufferView); } break; - case DescriptorSetInfo::DescriptorWriteType::InlineUniformBlock: + case DescriptorSetInfo::DescriptorWriteType::InlineUniformBlock: { + uint32_t dataSize = stream->getBe32(); + tmpInlineUniformBlockBuffers.push_back( + std::vector(dataSize)); + stream->read(tmpInlineUniformBlockBuffers.back().data(), dataSize); + tmpInlineUniformBlocks.push_back( + std::make_unique()); + VkWriteDescriptorSetInlineUniformBlockEXT& inlineUniformBlock = + *tmpInlineUniformBlocks.back(); + inlineUniformBlock.sType = + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT; + inlineUniformBlock.pNext = nullptr; + inlineUniformBlock.dataSize = dataSize; + inlineUniformBlock.pData = + tmpInlineUniformBlockBuffers.back().data(); + writeDescriptorSet.pNext = &inlineUniformBlock; + // Note: following is redundant, as arrayElement is guarantee to be + // 0 due to the way descriptor is handled in snapshot. it just + // serves to clarify that we are updating the whole buffer, to + // account the possibility of accumulative updating + writeDescriptorSet.dstArrayElement = 0; + // Note: following is important to indicate we are updating + // the whole buffer, as it could accumulate multiple update before + // snapshot is taken + writeDescriptorSet.descriptorCount = dataSize; + } break; case DescriptorSetInfo::DescriptorWriteType::AccelerationStructure: // TODO - GFXSTREAM_FATAL("Encountered pending inline uniform block or acceleration " - "structure desc write, abort (NYI)"); - break; + GFXSTREAM_ERROR( + "Encountered pending acceleration " + "structure desc write, abort (NYI)"); + return false; default: break; } @@ -1015,7 +1067,8 @@ class VkDecoderGlobalState::Impl { VkFence unboxedFence = unbox_VkFence(boxedFence); auto it = mFenceInfo.find(unboxedFence); if (it == mFenceInfo.end()) { - GFXSTREAM_FATAL("Snapshot load failure: unrecognized VkFence"); + GFXSTREAM_ERROR("Snapshot load failure: unrecognized VkFence"); + return false; } const auto& device = it->second.device; const auto& deviceInfo = gfxstream::base::find(mDeviceInfo, device); @@ -1038,6 +1091,7 @@ class VkDecoderGlobalState::Impl { mSnapshotState = SnapshotState::Normal; } GFXSTREAM_DEBUG("VulkanSnapshots load (end)"); + return true; } std::optional getContextIdForDeviceLocked(VkDevice device) REQUIRES(mMutex) { @@ -1162,8 +1216,8 @@ class VkDecoderGlobalState::Impl { info.applicationName.c_str(), info.engineName.c_str()); #ifdef CONFIG_AEMU - m_vkEmulation->getCallbacks().registerVulkanInstance((uint64_t)*pInstance, - info.applicationName.c_str()); + m_vkEmulation->getGlobalState()->registerVulkanInstance((uint64_t)*pInstance, + info.applicationName.c_str()); #endif // Box it up VkInstance boxed = new_boxed_VkInstance(*pInstance, nullptr); @@ -1186,7 +1240,7 @@ class VkDecoderGlobalState::Impl { *pInstance = (VkInstance)info.boxed; if (vkCleanupEnabled()) { - m_vkEmulation->getCallbacks().registerProcessCleanupCallback( + m_vkEmulation->getGlobalState()->registerProcessCleanupCallback( unbox_VkInstance(boxed), info.contextId, [this, boxed] { if (snapshotsEnabled()) { snapshot()->vkDestroyInstance(nullptr, kInvalidSnapshotApiCallHandle, nullptr, 0, boxed, nullptr); @@ -1245,7 +1299,7 @@ class VkDecoderGlobalState::Impl { } // The instance should not be used after vkDestroyInstanceImpl is called, // remove it from the cleanup callback mapping. - m_vkEmulation->getCallbacks().unregisterProcessCleanupCallback(instance); + m_vkEmulation->getGlobalState()->unregisterProcessCleanupCallback(instance); vkDestroyInstanceImpl(instance); } @@ -1937,10 +1991,6 @@ class VkDecoderGlobalState::Impl { shouldPassthrough = shouldPassthrough && !(m_vkEmulation->getExternalMemoryMode() == ExternalMemory::Mode::Metal); #endif - if (shouldPassthrough) { - return vk->vkEnumerateDeviceExtensionProperties(physicalDevice, pLayerName, - pPropertyCount, pProperties); - } #if defined(_WIN32) // Temporary fix to get old system images working with lavapipe @@ -1952,6 +2002,11 @@ class VkDecoderGlobalState::Impl { } #endif + if (shouldPassthrough) { + return vk->vkEnumerateDeviceExtensionProperties(physicalDevice, pLayerName, + pPropertyCount, pProperties); + } + // If MoltenVK is supported on host, we need to ensure that we include // VK_MVK_moltenvk extenstion in returned properties. std::vector properties; @@ -3002,6 +3057,18 @@ class VkDecoderGlobalState::Impl { return VK_ERROR_OUT_OF_HOST_MEMORY; } + // Change creation parameters before the validation checks below as the + // creation format and its device properties may change + const bool needDecompression = deviceInfo->needEmulatedDecompression(pCreateInfo->format); + std::unique_ptr cmpInfo = nullptr; + VkImageCreateInfo decompInfo; + if (needDecompression) { + cmpInfo = std::make_unique(device, *pCreateInfo, + deviceInfo->decompPipelines.get()); + decompInfo = cmpInfo->getOutputCreateInfo(*pCreateInfo); + pCreateInfo = &decompInfo; + } + #ifdef __APPLE__ // TODO(b/438924843) this is probably not optimal as it might slow down image creation a // bit. Not validating the dimensions seems to be only fatal on macOS, and can create false @@ -3028,8 +3095,10 @@ class VkDecoderGlobalState::Impl { if (res != VK_SUCCESS) { GFXSTREAM_WARNING( - "vkCreateImage: vkGetPhysicalDeviceImageFormatProperties failed with %s", - string_VkResult(res)); + "vkCreateImage: vkGetPhysicalDeviceImageFormatProperties failed with %s on " + "format %s[%d]", + string_VkResult(res), string_VkFormat(pCreateInfo->format), + pCreateInfo->format); return VK_ERROR_VALIDATION_FAILED_EXT; } @@ -3047,16 +3116,6 @@ class VkDecoderGlobalState::Impl { } #endif - const bool needDecompression = deviceInfo->needEmulatedDecompression(pCreateInfo->format); - std::unique_ptr cmpInfo = nullptr; - VkImageCreateInfo decompInfo; - if (needDecompression) { - cmpInfo = std::make_unique(device, *pCreateInfo, - deviceInfo->decompPipelines.get()); - decompInfo = cmpInfo->getOutputCreateInfo(*pCreateInfo); - pCreateInfo = &decompInfo; - } - std::unique_ptr anbInfo = nullptr; const VkNativeBufferANDROID* nativeBufferANDROID = vk_find_struct(pCreateInfo); @@ -3155,6 +3214,11 @@ class VkDecoderGlobalState::Impl { auto original_underlying_image = bimi->image; auto original_boxed_image = unboxed_to_boxed_non_dispatchable_VkImage(original_underlying_image); + if (!original_boxed_image) { + GFXSTREAM_ERROR("Original boxed image not found for deferred AHB bind."); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + VkImageCreateInfo ici = {}; { std::lock_guard lock(mMutex); @@ -4619,31 +4683,17 @@ class VkDecoderGlobalState::Impl { static DescriptorSetInfo::DescriptorWrite* GetDescriptorSetElementEntryWrapping( std::vector>& descriptorSetTable, uint32_t& bindingIndex, uint32_t& arrayElementIndex) { - if (bindingIndex >= descriptorSetTable.size()) { - return nullptr; - } - - std::vector& bindingTable = - descriptorSetTable[bindingIndex]; - if (arrayElementIndex < bindingTable.size()) { - return &bindingTable[arrayElementIndex]; - } - - // Descriptor writes wrap to the next binding. See - // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkWriteDescriptorSet.html - ++bindingIndex; - arrayElementIndex = 0; - - if (bindingIndex >= descriptorSetTable.size()) { - return nullptr; - } - - std::vector& nextBindingTable = - descriptorSetTable[bindingIndex]; - if (arrayElementIndex < nextBindingTable.size()) { - return &nextBindingTable[arrayElementIndex]; + while (bindingIndex < descriptorSetTable.size()) { + std::vector& bindingTable = + descriptorSetTable[bindingIndex]; + if (arrayElementIndex < bindingTable.size()) { + return &bindingTable[arrayElementIndex]; + } + // Descriptor writes wrap to the next binding. See + // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkWriteDescriptorSet.html + ++bindingIndex; + arrayElementIndex = 0; } - return nullptr; } @@ -4748,10 +4798,13 @@ class VkDecoderGlobalState::Impl { if (entry == nullptr) break; entry->inlineUniformBlock = *descInlineUniformBlock; - entry->inlineUniformBlockBuffer.assign( - static_cast(descInlineUniformBlock->pData), - static_cast(descInlineUniformBlock->pData) + - descInlineUniformBlock->dataSize); + if (entry->inlineUniformBlockBuffer.size() < + dstArrayElement + descInlineUniformBlock->dataSize) { + entry->inlineUniformBlockBuffer.resize(dstArrayElement + + descInlineUniformBlock->dataSize); + } + memcpy(entry->inlineUniformBlockBuffer.data() + dstArrayElement, + descInlineUniformBlock->pData, descInlineUniformBlock->dataSize); entry->writeType = DescriptorSetInfo::DescriptorWriteType::InlineUniformBlock; entry->descriptorType = descType; entry->dstArrayElement = dstArrayElement; @@ -4766,11 +4819,80 @@ class VkDecoderGlobalState::Impl { } } } - // TODO: bookkeep pDescriptorCopies - // Our primary use case vkQueueCommitDescriptorSetUpdatesGOOGLE does not use - // pDescriptorCopies. Thus skip its implementation for now. - if (descriptorCopyCount && snapshotsEnabled()) { - GFXSTREAM_ERROR("%s: Snapshot does not support descriptor copy yet\n"); + for (uint32_t copyIdx = 0; copyIdx < descriptorCopyCount; copyIdx++) { + const VkCopyDescriptorSet& descriptorCopy = pDescriptorCopies[copyIdx]; + auto srcIte = mDescriptorSetInfo.find(descriptorCopy.srcSet); + if (srcIte == mDescriptorSetInfo.end()) { + continue; + } + auto dstIte = mDescriptorSetInfo.find(descriptorCopy.dstSet); + if (dstIte == mDescriptorSetInfo.end()) { + continue; + } + + DescriptorSetInfo& srcDescriptorSetInfo = srcIte->second; + DescriptorSetInfo& dstDescriptorSetInfo = dstIte->second; + + auto& srcTable = srcDescriptorSetInfo.allWrites; + auto& dstTable = dstDescriptorSetInfo.allWrites; + + uint32_t srcBinding = descriptorCopy.srcBinding; + uint32_t srcArrayElement = descriptorCopy.srcArrayElement; + uint32_t dstBinding = descriptorCopy.dstBinding; + uint32_t dstArrayElement = descriptorCopy.dstArrayElement; + uint32_t descriptorCount = descriptorCopy.descriptorCount; + + uint32_t srcBindingCheck = srcBinding; + uint32_t srcArrayElementCheck = srcArrayElement; + auto* srcCheckEntry = GetDescriptorSetElementEntryWrapping(srcTable, srcBindingCheck, + srcArrayElementCheck); + + uint32_t dstBindingCheck = dstBinding; + uint32_t dstArrayElementCheck = dstArrayElement; + auto* dstCheckEntry = GetDescriptorSetElementEntryWrapping(dstTable, dstBindingCheck, + dstArrayElementCheck); + + if (srcCheckEntry && dstCheckEntry && + isDescriptorTypeInlineUniformBlock(srcCheckEntry->descriptorType)) { + uint32_t zero1 = 0; + uint32_t zero2 = 0; + auto* srcEntry = + GetDescriptorSetElementEntryWrapping(srcTable, srcBindingCheck, zero1); + auto* dstEntry = + GetDescriptorSetElementEntryWrapping(dstTable, dstBindingCheck, zero2); + + if (srcEntry && dstEntry) { + if (dstEntry->inlineUniformBlockBuffer.size() < + dstArrayElementCheck + descriptorCount) { + dstEntry->inlineUniformBlockBuffer.resize(dstArrayElementCheck + + descriptorCount); + } + if (srcEntry->inlineUniformBlockBuffer.size() > srcArrayElementCheck) { + uint32_t copySize = std::min( + descriptorCount, (uint32_t)srcEntry->inlineUniformBlockBuffer.size() - + srcArrayElementCheck); + memcpy(dstEntry->inlineUniformBlockBuffer.data() + dstArrayElementCheck, + srcEntry->inlineUniformBlockBuffer.data() + srcArrayElementCheck, + copySize); + } + dstEntry->writeType = + DescriptorSetInfo::DescriptorWriteType::InlineUniformBlock; + dstEntry->descriptorType = srcEntry->descriptorType; + } + continue; + } + + for (uint32_t writeElemIdx = 0; writeElemIdx < descriptorCount; + ++writeElemIdx, ++srcArrayElement, ++dstArrayElement) { + auto* srcEntry = + GetDescriptorSetElementEntryWrapping(srcTable, srcBinding, srcArrayElement); + auto* dstEntry = + GetDescriptorSetElementEntryWrapping(dstTable, dstBinding, dstArrayElement); + + if (srcEntry == nullptr || dstEntry == nullptr) break; + + *dstEntry = *srcEntry; + } } bool needEmulateWriteDescriptor = false; // c++ seems to allow for 0-size array allocation @@ -6000,15 +6122,14 @@ class VkDecoderGlobalState::Impl { info->guestPhysAddr = physAddr; - constexpr size_t kPageBits = 12; - constexpr size_t kPageSize = 1u << kPageBits; - constexpr size_t kPageOffsetMask = kPageSize - 1; + const size_t pageSize = gfxstream::host::get_gfxstream_guest_page_size(); + const size_t pageOffsetMask = pageSize - 1; uintptr_t addr = reinterpret_cast(info->ptr); - uintptr_t pageOffset = addr & kPageOffsetMask; + uintptr_t pageOffset = addr & pageOffsetMask; info->pageAlignedHva = reinterpret_cast(addr - pageOffset); - info->sizeToPage = ((info->size + pageOffset + kPageSize - 1) >> kPageBits) << kPageBits; + info->sizeToPage = (info->size + pageOffset + pageSize - 1) & ~pageOffsetMask; if (mLogging) { GFXSTREAM_VERBOSE("%s: map: %p, %p -> [0x%llx 0x%llx]", __func__, info->ptr, @@ -6193,7 +6314,7 @@ class VkDecoderGlobalState::Impl { shouldUseDedicatedAllocInfo &= colorBufferMemoryUsesDedicatedAlloc; if (!m_vkEmulation->getFeatures().GuestVulkanOnly.enabled()) { - m_vkEmulation->getCallbacks().invalidateColorBuffer( + m_vkEmulation->getGlobalState()->invalidateColorBuffer( importCbInfoPtr->colorBuffer); } @@ -6583,9 +6704,10 @@ class VkDecoderGlobalState::Impl { // Determine size and alignment requirements and allocate a PrivateMemory VkDeviceSize alignmentSize = m_vkEmulation->externalMemoryHostProperties().minImportedHostPointerAlignment; - if (createBlobInfoPtr && alignmentSize < kPageSizeforBlob) { + const size_t guestPageSize = gfxstream::host::get_gfxstream_guest_page_size(); + if (createBlobInfoPtr && alignmentSize < guestPageSize) { // Align blob allocations to the page size - alignmentSize = kPageSizeforBlob; + alignmentSize = guestPageSize; } VkDeviceSize alignedSize = ALIGN(localAllocInfo.allocationSize, alignmentSize); @@ -7662,7 +7784,7 @@ class VkDecoderGlobalState::Impl { } for (HandleType cb : acquiredColorBuffers) { - m_vkEmulation->getCallbacks().invalidateColorBuffer(cb); + m_vkEmulation->getGlobalState()->invalidateColorBuffer(cb); } if (m_vkEmulation->getFeatures().VulkanDisableCoherentMemoryAndEmulate.enabled()) { @@ -7829,7 +7951,7 @@ class VkDecoderGlobalState::Impl { string_VkResult(result), result); } else { for (HandleType cb : releasedColorBuffers) { - m_vkEmulation->getCallbacks().flushColorBuffer(cb); + m_vkEmulation->getGlobalState()->flushColorBuffer(cb); } } } else { @@ -10679,7 +10801,7 @@ class VkDecoderGlobalState::Impl { instanceInfo.applicationName.c_str(), instanceInfo.engineName.c_str()); #ifdef CONFIG_AEMU - m_vkEmulation->getCallbacks().unregisterVulkanInstance((uint64_t)instance); + m_vkEmulation->getGlobalState()->unregisterVulkanInstance((uint64_t)instance); #endif delete_VkInstance(instanceInfo.boxed); LOG_CALLS_VERBOSE("destroyInstanceObjects: finished."); @@ -11120,10 +11242,12 @@ const gfxstream::host::FeatureSet& VkDecoderGlobalState::getFeatures() const { r bool VkDecoderGlobalState::vkCleanupEnabled() const { return mImpl->vkCleanupEnabled(); } -void VkDecoderGlobalState::save(gfxstream::Stream* stream) { mImpl->save(stream); } +bool VkDecoderGlobalState::save(gfxstream::Stream* stream) { + return mImpl->save(stream); +} -void VkDecoderGlobalState::load(gfxstream::Stream* stream, GfxApiLogger& gfxLogger) { - mImpl->load(stream, gfxLogger); +bool VkDecoderGlobalState::load(gfxstream::Stream* stream, GfxApiLogger& gfxLogger) { + return mImpl->load(stream, gfxLogger); } PFN_vkVoidFunction VkDecoderGlobalState::on_vkGetInstanceProcAddr( diff --git a/host/vulkan/vk_decoder_global_state.h b/host/vulkan/vk_decoder_global_state.h index 8e8429fd8..204e2e51b 100644 --- a/host/vulkan/vk_decoder_global_state.h +++ b/host/vulkan/vk_decoder_global_state.h @@ -89,8 +89,8 @@ class VkDecoderGlobalState { // bug 149997534 bool vkCleanupEnabled() const; - void save(gfxstream::Stream* stream); - void load(gfxstream::Stream* stream, gfxstream::host::GfxApiLogger& gfxLogger); + bool save(gfxstream::Stream* stream); + bool load(gfxstream::Stream* stream, gfxstream::host::GfxApiLogger& gfxLogger); PFN_vkVoidFunction on_vkGetInstanceProcAddr(gfxstream::base::BumpPool* pool, VkSnapshotApiCallHandle apiCallHandle, diff --git a/host/vulkan/vk_decoder_internal_structs.h b/host/vulkan/vk_decoder_internal_structs.h index db1dce285..42ef4a79b 100644 --- a/host/vulkan/vk_decoder_internal_structs.h +++ b/host/vulkan/vk_decoder_internal_structs.h @@ -29,20 +29,20 @@ #include #include +#include "common/goldfish_vk_deepcopy.h" #include "debug_utils_helper.h" #include "device_op_tracker.h" -#include "handle.h" -#include "vk_emulated_physical_device_memory.h" -#include "vk_emulated_physical_device_queue.h" -#include "render-utils/stream.h" +#include "emulated_textures/compressed_image_info.h" #include "gfxstream/common/logging.h" +#include "gfxstream/host/handle.h" #include "gfxstream/memory/SharedMemory.h" #include "gfxstream/synchronization/ConditionVariable.h" #include "gfxstream/synchronization/Lock.h" -#include "common/goldfish_vk_deepcopy.h" -#include "vulkan/vk_android_native_buffer_operations.h" -#include "vulkan/vk_format_utils.h" -#include "vulkan/emulated_textures/compressed_image_info.h" +#include "render-utils/stream.h" +#include "vk_android_native_buffer_operations.h" +#include "vk_emulated_physical_device_memory.h" +#include "vk_emulated_physical_device_queue.h" +#include "vk_format_utils.h" namespace gfxstream { namespace host { diff --git a/host/vulkan/vk_decoder_snapshot_utils.cpp b/host/vulkan/vk_decoder_snapshot_utils.cpp index 993087125..675c016cd 100644 --- a/host/vulkan/vk_decoder_snapshot_utils.cpp +++ b/host/vulkan/vk_decoder_snapshot_utils.cpp @@ -12,12 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "vulkan/vk_decoder_snapshot_utils.h" +#include "vk_decoder_snapshot_utils.h" +#include "gfxstream/common/logging.h" #include "vk_common_operations.h" #include "vk_utils.h" #include "vulkan_boxed_handles.h" -#include "gfxstream/common/logging.h" namespace gfxstream { namespace host { @@ -54,16 +54,16 @@ constexpr uint32_t kBadImageSnapshot = 0xbaadbeef; constexpr uint32_t kGoodImageSnapshot = 0x900df00d; } // namespace -void saveImageContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkImage image, +bool saveImageContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkImage image, const ImageInfo* imageInfo) { if (imageInfo->layout == VK_IMAGE_LAYOUT_UNDEFINED) { stream->putBe32(kBadImageSnapshot); - return; + return true; } // TODO(b/333936705): snapshot multi-sample images if (imageInfo->imageCreateInfoShallow.samples != VK_SAMPLE_COUNT_1_BIT) { stream->putBe32(kBadImageSnapshot); - return; + return true; } VulkanDispatch* dispatch = stateBlock->deviceDispatch; @@ -73,7 +73,7 @@ void saveImageContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkImage if (!getFormatTransferInfo(imageCreateInfo.format, imageCreateInfo.extent, &transferInfo) || !transferInfo.stagingBufferCopySize) { stream->putBe32(kBadImageSnapshot); - return; + return true; } VkDeviceSize stagingBufferSize = transferInfo.stagingBufferCopySize; @@ -123,8 +123,11 @@ void saveImageContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkImage dispatch->vkBindBufferMemory(stateBlock->device, readbackBuffer, readbackMemory, 0)); void* mapped = nullptr; - VK_CHECK(dispatch->vkMapMemory(stateBlock->device, readbackMemory, 0, VK_WHOLE_SIZE, - VkMemoryMapFlags{}, &mapped)); + if (dispatch->vkMapMemory(stateBlock->device, readbackMemory, 0, VK_WHOLE_SIZE, + VkMemoryMapFlags{}, &mapped) != VK_SUCCESS || mapped == nullptr) { + GFXSTREAM_ERROR("Failed to map memory for image snapshot save"); + return false; + } for (uint32_t mipLevel = 0; mipLevel < imageInfo->imageCreateInfoShallow.mipLevels; mipLevel++) { @@ -135,12 +138,14 @@ void saveImageContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkImage .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, }; if (dispatch->vkBeginCommandBuffer(commandBuffer, &beginInfo) != VK_SUCCESS) { - GFXSTREAM_FATAL("Failed to start command buffer on snapshot save"); + GFXSTREAM_ERROR("Failed to start command buffer on snapshot save"); + return false; } VkExtent3D mipmapExtent = getMipmapExtent(imageCreateInfo.extent, mipLevel); if (!getFormatTransferInfo(imageCreateInfo.format, mipmapExtent, &transferInfo)) { - GFXSTREAM_FATAL("Failed to get transfer info for snapshot save"); + GFXSTREAM_ERROR("Failed to get transfer info for snapshot save"); + return false; } VkDeviceSize mipmapStagingBufferSize = transferInfo.stagingBufferCopySize; std::vector& bufferImageCopies = transferInfo.bufferImageCopies; @@ -209,13 +214,14 @@ void saveImageContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkImage dispatch->vkDestroyBuffer(stateBlock->device, readbackBuffer, nullptr); dispatch->vkFreeMemory(stateBlock->device, readbackMemory, nullptr); dispatch->vkFreeCommandBuffers(stateBlock->device, stateBlock->commandPool, 1, &commandBuffer); + return true; } -void loadImageContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkImage image, +bool loadImageContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkImage image, const ImageInfo* imageInfo) { const bool validImage = (stream->getBe32() == kGoodImageSnapshot); if (!validImage) { - return; + return true; } VulkanDispatch* dispatch = stateBlock->deviceDispatch; @@ -223,7 +229,7 @@ void loadImageContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkImage TransferInfo transferInfo; if (!getFormatTransferInfo(imageCreateInfo.format, imageCreateInfo.extent, &transferInfo)) { - return; + return true; } VkDeviceSize stagingBufferSize = transferInfo.stagingBufferCopySize; @@ -287,7 +293,7 @@ void loadImageContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkImage dispatch->vkDestroyFence(stateBlock->device, fence, nullptr); dispatch->vkFreeCommandBuffers(stateBlock->device, stateBlock->commandPool, 1, &commandBuffer); - return; + return true; } VkBufferCreateInfo bufferCreateInfo = { .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, @@ -321,8 +327,11 @@ void loadImageContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkImage dispatch->vkBindBufferMemory(stateBlock->device, stagingBuffer, stagingMemory, 0)); void* mapped = nullptr; - VK_CHECK(dispatch->vkMapMemory(stateBlock->device, stagingMemory, 0, VK_WHOLE_SIZE, - VkMemoryMapFlags{}, &mapped)); + if (dispatch->vkMapMemory(stateBlock->device, stagingMemory, 0, VK_WHOLE_SIZE, + VkMemoryMapFlags{}, &mapped) != VK_SUCCESS || mapped == nullptr) { + GFXSTREAM_ERROR("Failed to map memory for image snapshot load"); + return false; + } for (uint32_t mipLevel = 0; mipLevel < imageInfo->imageCreateInfoShallow.mipLevels; mipLevel++) { @@ -333,12 +342,14 @@ void loadImageContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkImage .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, }; if (dispatch->vkBeginCommandBuffer(commandBuffer, &beginInfo) != VK_SUCCESS) { - GFXSTREAM_FATAL("Failed to start command buffer on snapshot save"); + GFXSTREAM_ERROR("Failed to start command buffer on snapshot load"); + return false; } VkExtent3D mipmapExtent = getMipmapExtent(imageCreateInfo.extent, mipLevel); if (!getFormatTransferInfo(imageCreateInfo.format, mipmapExtent, &transferInfo)) { - GFXSTREAM_FATAL("Failed to get transfer info for snapshot load"); + GFXSTREAM_ERROR("Failed to get transfer info for snapshot load"); + return false; } // Require the serialized size to match the expected per-mip transfer size. @@ -408,14 +419,15 @@ void loadImageContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkImage dispatch->vkDestroyBuffer(stateBlock->device, stagingBuffer, nullptr); dispatch->vkFreeMemory(stateBlock->device, stagingMemory, nullptr); dispatch->vkFreeCommandBuffers(stateBlock->device, stateBlock->commandPool, 1, &commandBuffer); + return true; } -void saveBufferContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkBuffer buffer, +bool saveBufferContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkBuffer buffer, const BufferInfo* bufferInfo) { VkBufferUsageFlags requiredUsages = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; if ((bufferInfo->usage & requiredUsages) != requiredUsages) { - return; + return true; } VulkanDispatch* dispatch = stateBlock->deviceDispatch; VkCommandBufferAllocateInfo allocInfo{ @@ -463,8 +475,11 @@ void saveBufferContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkBuff dispatch->vkBindBufferMemory(stateBlock->device, readbackBuffer, readbackMemory, 0)); void* mapped = nullptr; - VK_CHECK(dispatch->vkMapMemory(stateBlock->device, readbackMemory, 0, VK_WHOLE_SIZE, - VkMemoryMapFlags{}, &mapped)); + if (dispatch->vkMapMemory(stateBlock->device, readbackMemory, 0, VK_WHOLE_SIZE, + VkMemoryMapFlags{}, &mapped) != VK_SUCCESS || mapped == nullptr) { + GFXSTREAM_ERROR("Failed to map memory for buffer snapshot save"); + return false; + } VkBufferCopy bufferCopy = { .srcOffset = 0, @@ -476,7 +491,8 @@ void saveBufferContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkBuff .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, }; if (dispatch->vkBeginCommandBuffer(commandBuffer, &beginInfo) != VK_SUCCESS) { - GFXSTREAM_FATAL("Failed to start command buffer on snapshot save"); + GFXSTREAM_ERROR("Failed to start command buffer on snapshot save"); + return false; } dispatch->vkCmdCopyBuffer(commandBuffer, buffer, readbackBuffer, 1, &bufferCopy); VkBufferMemoryBarrier barrier{.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, @@ -510,6 +526,7 @@ void saveBufferContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkBuff dispatch->vkDestroyBuffer(stateBlock->device, readbackBuffer, nullptr); dispatch->vkFreeMemory(stateBlock->device, readbackMemory, nullptr); dispatch->vkFreeCommandBuffers(stateBlock->device, stateBlock->commandPool, 1, &commandBuffer); + return true; } void setEventInQueue(StateBlock* stateBlock, VkEvent event, uint64_t eventflags) { @@ -570,12 +587,12 @@ void signalSemaphore(StateBlock* stateBlock, VkSemaphore unboxed_semaphore) { dispatch->vkDestroyFence(stateBlock->device, fence, nullptr); } -void loadBufferContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkBuffer buffer, +bool loadBufferContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkBuffer buffer, const BufferInfo* bufferInfo) { VkBufferUsageFlags requiredUsages = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; if ((bufferInfo->usage & requiredUsages) != requiredUsages) { - return; + return true; } VulkanDispatch* dispatch = stateBlock->deviceDispatch; VkCommandBufferAllocateInfo allocInfo{ @@ -623,11 +640,15 @@ void loadBufferContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkBuff dispatch->vkBindBufferMemory(stateBlock->device, stagingBuffer, stagingMemory, 0)); void* mapped = nullptr; - VK_CHECK(dispatch->vkMapMemory(stateBlock->device, stagingMemory, 0, VK_WHOLE_SIZE, - VkMemoryMapFlags{}, &mapped)); + if (dispatch->vkMapMemory(stateBlock->device, stagingMemory, 0, VK_WHOLE_SIZE, + VkMemoryMapFlags{}, &mapped) != VK_SUCCESS || mapped == nullptr) { + GFXSTREAM_ERROR("Failed to map memory for buffer snapshot load"); + return false; + } size_t bufferSize = stream->getBe64(); if (bufferSize != bufferInfo->size) { - GFXSTREAM_FATAL("Failed to read buffer on snapshot load"); + GFXSTREAM_ERROR("Failed to read buffer on snapshot load"); + return false; } stream->read(mapped, bufferInfo->size); @@ -641,7 +662,8 @@ void loadBufferContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkBuff .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, }; if (dispatch->vkBeginCommandBuffer(commandBuffer, &beginInfo) != VK_SUCCESS) { - GFXSTREAM_FATAL("Failed to start command buffer on snapshot load"); + GFXSTREAM_ERROR("Failed to start command buffer on snapshot load"); + return false; } dispatch->vkCmdCopyBuffer(commandBuffer, stagingBuffer, buffer, 1, &bufferCopy); VkBufferMemoryBarrier barrier{.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, @@ -673,6 +695,7 @@ void loadBufferContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkBuff dispatch->vkDestroyBuffer(stateBlock->device, stagingBuffer, nullptr); dispatch->vkFreeMemory(stateBlock->device, stagingMemory, nullptr); dispatch->vkFreeCommandBuffers(stateBlock->device, stateBlock->commandPool, 1, &commandBuffer); + return true; } } // namespace vk diff --git a/host/vulkan/vk_decoder_snapshot_utils.h b/host/vulkan/vk_decoder_snapshot_utils.h index 9d4f2c9b0..7c34d9ecf 100644 --- a/host/vulkan/vk_decoder_snapshot_utils.h +++ b/host/vulkan/vk_decoder_snapshot_utils.h @@ -14,7 +14,7 @@ #pragma once -#include "vulkan/vk_decoder_internal_structs.h" +#include "vk_decoder_internal_structs.h" namespace gfxstream { namespace host { @@ -27,18 +27,18 @@ struct StateBlock { VkQueue queue; VkCommandPool commandPool; }; -void saveImageContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkImage image, +bool saveImageContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkImage image, const ImageInfo* imageInfo); -void loadImageContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkImage image, +bool loadImageContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkImage image, const ImageInfo* imageInfo); -void saveBufferContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkBuffer buffer, +bool saveBufferContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkBuffer buffer, const BufferInfo* bufferInfo); void setEventInQueue(StateBlock* stateBlock, VkEvent event, uint64_t eventflags); void signalSemaphore(StateBlock* stateBlock, VkSemaphore unboxed_semaphore); -void loadBufferContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkBuffer buffer, +bool loadBufferContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkBuffer buffer, const BufferInfo* bufferInfo); } // namespace vk } // namespace host diff --git a/host/vulkan/vk_emulated_physical_device_memory.cpp b/host/vulkan/vk_emulated_physical_device_memory.cpp index eda5b8122..0006d0a7e 100644 --- a/host/vulkan/vk_emulated_physical_device_memory.cpp +++ b/host/vulkan/vk_emulated_physical_device_memory.cpp @@ -30,9 +30,7 @@ static constexpr const uint32_t kInvalidMemoryTypeIndex = std::numeric_limits mMaxSafeHeapSize) { - mGuestMemoryProperties.memoryHeaps[i].size = mMaxSafeHeapSize; + // Limit max safe memory heap size if the VulkanMaxSafeHeapSize feature is set to a non-zero + // value. + const uint64_t maxSafeHeapSizeLimit = features.VulkanMaxSafeHeapSize.getValue().value_or(0); + if (maxSafeHeapSizeLimit > 0) { + for (uint32_t i = 0; i < mHostMemoryProperties.memoryHeapCount; i++) { + if (mGuestMemoryProperties.memoryHeaps[i].size > maxSafeHeapSizeLimit) { + mGuestMemoryProperties.memoryHeaps[i].size = maxSafeHeapSizeLimit; + } } } @@ -82,10 +83,13 @@ EmulatedPhysicalDeviceMemoryProperties::EmulatedPhysicalDeviceMemoryProperties( // Let cached memory pretend as coherent on the guest side. if (features.VulkanDisableCoherentMemoryAndEmulate.enabled()) { for (uint32_t i = 0; i < mGuestMemoryProperties.memoryTypeCount; i++) { - if (mGuestMemoryProperties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) { - mGuestMemoryProperties.memoryTypes[i].propertyFlags |= VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + if (mGuestMemoryProperties.memoryTypes[i].propertyFlags & + VK_MEMORY_PROPERTY_HOST_CACHED_BIT) { + mGuestMemoryProperties.memoryTypes[i].propertyFlags |= + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; } else { - mGuestMemoryProperties.memoryTypes[i].propertyFlags &= ~(VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + mGuestMemoryProperties.memoryTypes[i].propertyFlags &= + ~(VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); } } } @@ -131,8 +135,9 @@ EmulatedPhysicalDeviceMemoryProperties::EmulatedPhysicalDeviceMemoryProperties( // memory. if (features.VulkanUseDedicatedAhbMemoryType.enabled()) { if (mGuestMemoryProperties.memoryTypeCount == VK_MAX_MEMORY_TYPES) { - GFXSTREAM_FATAL("Unable to create emulated AHB memory type because VK_MAX_MEMORY_TYPES " - "already in use."); + GFXSTREAM_FATAL( + "Unable to create emulated AHB memory type because VK_MAX_MEMORY_TYPES " + "already in use."); } uint32_t ahbMemoryTypeIndex = mGuestMemoryProperties.memoryTypeCount; diff --git a/host/vulkan/vk_emulated_physical_device_memory.h b/host/vulkan/vk_emulated_physical_device_memory.h index b130f096b..9d344dc5f 100644 --- a/host/vulkan/vk_emulated_physical_device_memory.h +++ b/host/vulkan/vk_emulated_physical_device_memory.h @@ -30,14 +30,9 @@ namespace vk { // guest, and helps to convert between both. class EmulatedPhysicalDeviceMemoryProperties { public: - // Hide any bogus heap sizes from bad drivers with a reasonable default that will not - // break the bank on 32-bit userspaces. - static constexpr VkDeviceSize kDefaultMaxSafeHeapSize = 2ULL * 1024ULL * 1024ULL * 1024ULL; - EmulatedPhysicalDeviceMemoryProperties(const VkPhysicalDeviceMemoryProperties& host, uint32_t hostColorBufferMemoryTypeIndex, - const gfxstream::host::FeatureSet& features, - VkDeviceSize maxSafeHeapSize = kDefaultMaxSafeHeapSize); + const gfxstream::host::FeatureSet& features); struct HostMemoryInfo { uint32_t index; @@ -55,9 +50,7 @@ class EmulatedPhysicalDeviceMemoryProperties { return mHostMemoryProperties; } - uint32_t getGuestColorBufferMemoryTypeIndex() const { - return mGuestColorBufferMemoryTypeIndex; - } + uint32_t getGuestColorBufferMemoryTypeIndex() const { return mGuestColorBufferMemoryTypeIndex; } void transformToGuestMemoryRequirements(VkMemoryRequirements* hostMemoryRequirements) const; @@ -66,7 +59,6 @@ class EmulatedPhysicalDeviceMemoryProperties { VkPhysicalDeviceMemoryBudgetPropertiesEXT* budgetProps) const; private: - VkDeviceSize mMaxSafeHeapSize; VkPhysicalDeviceMemoryProperties mGuestMemoryProperties; VkPhysicalDeviceMemoryProperties mHostMemoryProperties; uint32_t mGuestToHostMemoryTypeIndexMap[VK_MAX_MEMORY_TYPES]; diff --git a/host/vulkan/vk_emulated_physical_device_memory_tests.cpp b/host/vulkan/vk_emulated_physical_device_memory_tests.cpp index b4ac86fef..cb8167f5b 100644 --- a/host/vulkan/vk_emulated_physical_device_memory_tests.cpp +++ b/host/vulkan/vk_emulated_physical_device_memory_tests.cpp @@ -17,8 +17,8 @@ #include -#include "vk_emulated_physical_device_memory.h" #include "gfxstream/host/features.h" +#include "vk_emulated_physical_device_memory.h" namespace gfxstream { namespace host { @@ -259,6 +259,122 @@ TEST(VkGuestMemoryUtilsTest, VulkanAllocateDeviceMemoryOnly) { EXPECT_THAT(actualGuestMemoryProperties, EqsVkPhysicalDeviceMemoryProperties(expectedGuestMemoryProperties)); } + +TEST(VkGuestMemoryUtilsTest, VulkanMaxSafeHeapSizeUnset) { + const VkPhysicalDeviceMemoryProperties hostMemoryProperties = { + .memoryTypeCount = 1, + .memoryTypes = + { + { + .propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + .heapIndex = 0, + }, + }, + .memoryHeapCount = 2, + .memoryHeaps = + { + { + .size = 0x100000000ULL, // 4 GB + .flags = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT, + }, + { + .size = 0x200000000ULL, // 8 GB + .flags = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT, + }, + }, + }; + + gfxstream::host::FeatureSet features; + // VulkanMaxSafeHeapSize is left unset (default: zero, no limit) + + EmulatedPhysicalDeviceMemoryProperties helper(hostMemoryProperties, 0, features); + + const VkPhysicalDeviceMemoryProperties expectedGuestMemoryProperties = { + .memoryTypeCount = 1, + .memoryTypes = + { + { + .propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + .heapIndex = 0, + }, + }, + .memoryHeapCount = 2, + .memoryHeaps = + { + { + .size = 0x100000000ULL, + .flags = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT, + }, + { + .size = 0x200000000ULL, + .flags = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT, + }, + }, + }; + + const auto actualGuestMemoryProperties = helper.getGuestMemoryProperties(); + EXPECT_THAT(actualGuestMemoryProperties, + EqsVkPhysicalDeviceMemoryProperties(expectedGuestMemoryProperties)); +} + +TEST(VkGuestMemoryUtilsTest, VulkanMaxSafeHeapSizeSet) { + const VkPhysicalDeviceMemoryProperties hostMemoryProperties = { + .memoryTypeCount = 1, + .memoryTypes = + { + { + .propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + .heapIndex = 0, + }, + }, + .memoryHeapCount = 2, + .memoryHeaps = + { + { + .size = 0x100000000ULL, // 4 GB + .flags = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT, + }, + { + .size = 0x200000000ULL, // 8 GB + .flags = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT, + }, + }, + }; + + gfxstream::host::FeatureSet features; + // Set limit to 3 GB (0xC0000000 bytes) + features.VulkanMaxSafeHeapSize.parseValue("0xC0000000"); + + EmulatedPhysicalDeviceMemoryProperties helper(hostMemoryProperties, 0, features); + + const VkPhysicalDeviceMemoryProperties expectedGuestMemoryProperties = { + .memoryTypeCount = 1, + .memoryTypes = + { + { + .propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + .heapIndex = 0, + }, + }, + .memoryHeapCount = 2, + .memoryHeaps = + { + { + .size = 0xC0000000ULL, // Limited to 3 GB + .flags = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT, + }, + { + .size = 0xC0000000ULL, // Limited to 3 GB + .flags = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT, + }, + }, + }; + + const auto actualGuestMemoryProperties = helper.getGuestMemoryProperties(); + EXPECT_THAT(actualGuestMemoryProperties, + EqsVkPhysicalDeviceMemoryProperties(expectedGuestMemoryProperties)); +} + TEST(VkGuestMemoryUtilsTest, VulkanDisableCoherentMemoryAndEmulate) { const VkPhysicalDeviceMemoryProperties hostMemoryProperties = { .memoryTypeCount = 4, @@ -406,39 +522,40 @@ TEST(VkGuestMemoryUtilsTest, VulkanAMDCoherentFlagsNotLeakedToGuest) { // Standard types (types 0-3): hostMemoryProperties.memoryTypes[0] = {.propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, .heapIndex = 1}; - hostMemoryProperties.memoryTypes[1] = {.propertyFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, - .heapIndex = 0}; + hostMemoryProperties.memoryTypes[1] = { + .propertyFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + .heapIndex = 0}; hostMemoryProperties.memoryTypes[2] = {.propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, .heapIndex = 1}; hostMemoryProperties.memoryTypes[3] = {.propertyFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | - VK_MEMORY_PROPERTY_HOST_CACHED_BIT, + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | + VK_MEMORY_PROPERTY_HOST_CACHED_BIT, .heapIndex = 0}; // AMD-specific types (types 4-7) with DEVICE_COHERENT and DEVICE_UNCACHED: - hostMemoryProperties.memoryTypes[4] = {.propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | - VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD | - VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD, - .heapIndex = 1}; - hostMemoryProperties.memoryTypes[5] = {.propertyFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | - VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD | - VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD, - .heapIndex = 0}; - hostMemoryProperties.memoryTypes[6] = {.propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | - VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD | - VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD, - .heapIndex = 1}; - hostMemoryProperties.memoryTypes[7] = {.propertyFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | - VK_MEMORY_PROPERTY_HOST_CACHED_BIT | - VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD | - VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD, - .heapIndex = 0}; + hostMemoryProperties.memoryTypes[4] = { + .propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | + VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD | + VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD, + .heapIndex = 1}; + hostMemoryProperties.memoryTypes[5] = { + .propertyFlags = + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | + VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD | VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD, + .heapIndex = 0}; + hostMemoryProperties.memoryTypes[6] = { + .propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | + VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD | + VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD, + .heapIndex = 1}; + hostMemoryProperties.memoryTypes[7] = { + .propertyFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT | + VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD | + VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD, + .heapIndex = 0}; gfxstream::host::FeatureSet features; EmulatedPhysicalDeviceMemoryProperties helper(hostMemoryProperties, 0, features); @@ -478,8 +595,7 @@ TEST(VkGuestMemoryUtilsTest, VulkanAMDCoherentFlagsNotLeakedToGuest) { } TEST(VkGuestMemoryUtilsTest, MemoryBudgetClampedToClampedGuestHeapSize) { - constexpr VkDeviceSize kMaxSafeHeapSize = - EmulatedPhysicalDeviceMemoryProperties::kDefaultMaxSafeHeapSize; + constexpr VkDeviceSize kMaxSafeHeapSize = 2ULL * 1024ULL * 1024ULL * 1024ULL; VkPhysicalDeviceMemoryProperties hostMemoryProperties = {}; hostMemoryProperties.memoryHeapCount = 2; @@ -491,6 +607,7 @@ TEST(VkGuestMemoryUtilsTest, MemoryBudgetClampedToClampedGuestHeapSize) { .heapIndex = 0}; gfxstream::host::FeatureSet features; + features.VulkanMaxSafeHeapSize.setValue(kMaxSafeHeapSize); EmulatedPhysicalDeviceMemoryProperties helper(hostMemoryProperties, 0, features); ASSERT_EQ(helper.getGuestMemoryProperties().memoryHeaps[0].size, kMaxSafeHeapSize); diff --git a/host/vulkan/vk_utils.cpp b/host/vulkan/vk_utils.cpp index 77f44253e..18b5335a9 100644 --- a/host/vulkan/vk_utils.cpp +++ b/host/vulkan/vk_utils.cpp @@ -404,6 +404,106 @@ bool YcbcrSamplerPool::getOrCreateSamplerInfo(GfxstreamFormat format, YCbCrSampl return true; } +void addNeededBarriersToUseImage(VkImage image, uint32_t preQueueFamilyIndex, + VkImageLayout preLayout, uint32_t postQueueFamilyIndex, + VkImageLayout postLayout, uint32_t usedQueueFamilyIndex, + VkImageLayout usedInitialImageLayout, + VkImageLayout usedFinalImageLayout, VkAccessFlags usedAccessMask, + std::vector* preUseQueueTransferBarriers, + std::vector* preUseLayoutTransitionBarriers, + std::vector* postUseLayoutTransitionBarriers, + std::vector* postUseQueueTransferBarriers) { + if (preQueueFamilyIndex != usedQueueFamilyIndex) { + const VkImageMemoryBarrier queueTransferBarrier = { + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, + .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, + .oldLayout = preLayout, + .newLayout = preLayout, + .srcQueueFamilyIndex = preQueueFamilyIndex, + .dstQueueFamilyIndex = usedQueueFamilyIndex, + .image = image, + .subresourceRange = + { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }, + }; + preUseQueueTransferBarriers->emplace_back(queueTransferBarrier); + } + if (preLayout != usedInitialImageLayout && + usedInitialImageLayout != VK_IMAGE_LAYOUT_UNDEFINED) { + const VkImageMemoryBarrier layoutTransitionBarrier = { + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, + .dstAccessMask = usedAccessMask, + .oldLayout = preLayout, + .newLayout = usedInitialImageLayout, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = image, + .subresourceRange = + { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }, + }; + preUseLayoutTransitionBarriers->emplace_back(layoutTransitionBarrier); + } + if (postLayout != usedFinalImageLayout) { + const VkImageMemoryBarrier layoutTransitionBarrier = { + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = usedAccessMask, + .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, + .oldLayout = usedFinalImageLayout, + .newLayout = postLayout, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = image, + .subresourceRange = + { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }, + }; + postUseLayoutTransitionBarriers->emplace_back(layoutTransitionBarrier); + } + if (postQueueFamilyIndex != usedQueueFamilyIndex) { + const VkImageMemoryBarrier queueTransferBarrier = { + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, + .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, + .oldLayout = postLayout, + .newLayout = postLayout, + .srcQueueFamilyIndex = usedQueueFamilyIndex, + .dstQueueFamilyIndex = postQueueFamilyIndex, + .image = image, + .subresourceRange = + { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }, + }; + postUseQueueTransferBarriers->emplace_back(queueTransferBarrier); + } +} + } // namespace vk_util } // namespace vk } // namespace host diff --git a/host/vulkan/vk_utils.h b/host/vulkan/vk_utils.h index 4ea1d8ed8..67bb09ccf 100644 --- a/host/vulkan/vk_utils.h +++ b/host/vulkan/vk_utils.h @@ -407,6 +407,16 @@ class YcbcrSamplerPool { std::unordered_map m_ycbcrSamplers GUARDED_BY(mMutex); }; +void addNeededBarriersToUseImage(VkImage image, uint32_t preQueueFamilyIndex, + VkImageLayout preLayout, uint32_t postQueueFamilyIndex, + VkImageLayout postLayout, uint32_t usedQueueFamilyIndex, + VkImageLayout usedInitialImageLayout, + VkImageLayout usedFinalImageLayout, VkAccessFlags usedAccessMask, + std::vector* preUseQueueTransferBarriers, + std::vector* preUseLayoutTransitionBarriers, + std::vector* postUseLayoutTransitionBarriers, + std::vector* postUseQueueTransferBarriers); + } // namespace vk_util } // namespace vk } // namespace host diff --git a/host/vulkan/vulkan_unittest.cpp b/host/vulkan/vulkan_unittest.cpp index 18e6b0f0c..b153ee307 100644 --- a/host/vulkan/vulkan_unittest.cpp +++ b/host/vulkan/vulkan_unittest.cpp @@ -14,19 +14,18 @@ #include +#include + #include #include -#include - -#include "frame_buffer.h" #include "OpenGLESDispatch/OpenGLDispatchLoader.h" -#include "vk_common_operations.h" -#include "vulkan_dispatch.h" #include "gfxstream/ArraySize.h" #include "gfxstream/files/PathUtils.h" -#include "gfxstream/system/System.h" #include "gfxstream/host/testing/VkTestUtils.h" +#include "gfxstream/system/System.h" +#include "vk_common_operations.h" +#include "vulkan_dispatch.h" #ifdef _WIN32 #include diff --git a/tests/end2end/gfxstream_end2end_composition_tests.cpp b/tests/end2end/gfxstream_end2end_composition_tests.cpp index 0ca46f114..499040647 100644 --- a/tests/end2end/gfxstream_end2end_composition_tests.cpp +++ b/tests/end2end/gfxstream_end2end_composition_tests.cpp @@ -235,6 +235,63 @@ TEST_P(GfxstreamEnd2EndCompositionTest, BlitYV12) { GFXSTREAM_ASSERT(AhbIsEntirely(resultAhb, rgbaColor)); } +TEST_P(GfxstreamEnd2EndCompositionTest, BlitYCbCr888420) { + constexpr const uint32_t kWidth = 32; + constexpr const uint32_t kHeight = 32; + + ScopedRenderControlDevice rcDevice(*mRc); + + const PixelR8G8B8A8 rgbaColor = PixelR8G8B8A8(66, 99, 160, 255); + + const auto yuvColor = PixelY8U8V8::FromR8G8B8A8(rgbaColor); + const auto yuvAhb = GFXSTREAM_ASSERT( + CreateAHBWithColor(kWidth, kHeight, GFXSTREAM_AHB_FORMAT_Y8Cb8Cr8_420, yuvColor)); + + auto resultAhb = GFXSTREAM_ASSERT(ScopedAHardwareBuffer::Allocate( + *mGralloc, kWidth, kHeight, GFXSTREAM_AHB_FORMAT_B8G8R8A8_UNORM)); + + const RenderControlComposition composition = { + .displayId = 0, + .compositionResultColorBufferHandle = mGralloc->getHostHandle(resultAhb), + }; + const std::vector compositionLayers = {{ + { + .colorBufferHandle = mGralloc->getHostHandle(yuvAhb), + .composeMode = HWC2_COMPOSITION_DEVICE, + .displayFrame = + { + .left = 0, + .top = 0, + .right = kWidth, + .bottom = kHeight, + }, + .crop = + { + .left = 0, + .top = 0, + .right = static_cast(kWidth), + .bottom = static_cast(kHeight), + }, + .blendMode = HWC2_BLEND_MODE_NONE, + .alpha = 1.0, + .color = + { + .r = 0, + .g = 0, + .b = 0, + .a = 0, + }, + .transform = static_cast(0), + }, + }}; + ASSERT_THAT( + mRc->rcCompose(rcDevice, &composition, static_cast(compositionLayers.size()), + compositionLayers.data()), + Eq(0)); + + GFXSTREAM_ASSERT(AhbIsEntirely(resultAhb, rgbaColor)); +} + TEST_P(GfxstreamEnd2EndCompositionTest, BasicCompositionYV12) { ScopedRenderControlDevice rcDevice(*mRc); @@ -316,6 +373,87 @@ TEST_P(GfxstreamEnd2EndCompositionTest, BasicCompositionYV12) { GFXSTREAM_ASSERT(CompareAHBWithGolden(resultAhb, "256x256_golden_basic_yv12.png")); } +TEST_P(GfxstreamEnd2EndCompositionTest, BasicCompositionYCbCr888420) { + ScopedRenderControlDevice rcDevice(*mRc); + + auto layer1Ahb = GFXSTREAM_ASSERT(CreateAHBFromImage("256x256_android.png")); + + const auto layer2RgbaColor = PixelR8G8B8A8(66, 99, 160, 255); + const auto layer2YuvColor = PixelY8U8V8::FromR8G8B8A8(layer2RgbaColor); + auto layer2Ahb = + GFXSTREAM_ASSERT(CreateAHBWithColor(32, 32, GFXSTREAM_AHB_FORMAT_Y8Cb8Cr8_420, layer2YuvColor)); + + auto resultAhb = GFXSTREAM_ASSERT( + ScopedAHardwareBuffer::Allocate(*mGralloc, 256, 256, GFXSTREAM_AHB_FORMAT_B8G8R8A8_UNORM)); + + const RenderControlComposition composition = { + .displayId = 0, + .compositionResultColorBufferHandle = mGralloc->getHostHandle(resultAhb), + }; + const RenderControlCompositionLayer compositionLayers[2] = { + { + .colorBufferHandle = mGralloc->getHostHandle(layer1Ahb), + .composeMode = HWC2_COMPOSITION_DEVICE, + .displayFrame = + { + .left = 0, + .top = 0, + .right = 256, + .bottom = 256, + }, + .crop = + { + .left = 0, + .top = 0, + .right = static_cast(256), + .bottom = static_cast(256), + }, + .blendMode = HWC2_BLEND_MODE_NONE, + .alpha = 1.0, + .color = + { + .r = 0, + .g = 0, + .b = 0, + .a = 0, + }, + .transform = static_cast(0), + }, + { + .colorBufferHandle = mGralloc->getHostHandle(layer2Ahb), + .composeMode = HWC2_COMPOSITION_DEVICE, + .displayFrame = + { + .left = 64, + .top = 32, + .right = 128, + .bottom = 160, + }, + .crop = + { + .left = 0, + .top = 0, + .right = static_cast(256), + .bottom = static_cast(256), + }, + .blendMode = HWC2_BLEND_MODE_NONE, + .alpha = 1.0, + .color = + { + .r = 0, + .g = 0, + .b = 0, + .a = 0, + }, + .transform = static_cast(0), + }, + }; + + ASSERT_THAT(mRc->rcCompose(rcDevice, &composition, 2, compositionLayers), Eq(0)); + + GFXSTREAM_ASSERT(CompareAHBWithGolden(resultAhb, "256x256_golden_basic_yv12.png")); +} + TEST_P(GfxstreamEnd2EndCompositionTest, RotatedCompositionRGBA) { ScopedRenderControlDevice rcDevice(*mRc); @@ -478,6 +616,88 @@ TEST_P(GfxstreamEnd2EndCompositionTest, RotatedCompositionYV12) { GFXSTREAM_ASSERT(CompareAHBWithGolden(resultAhb, "256x256_golden_rotated_yv12.png")); } +TEST_P(GfxstreamEnd2EndCompositionTest, RotatedCompositionYCbCr888420) { + ScopedRenderControlDevice rcDevice(*mRc); + + const auto rgbaColor1 = PixelR8G8B8A8(66, 99, 160, 255); + const auto rgbaColor2 = PixelR8G8B8A8(222, 16, 0, 255); + const auto yuvColor1 = PixelY8U8V8::FromR8G8B8A8(rgbaColor1); + const auto yuvColor2 = PixelY8U8V8::FromR8G8B8A8(rgbaColor2); + + auto layer1Ahb = GFXSTREAM_ASSERT(CreateAHBFromImage("256x256_android.png")); + auto layer2Ahb = GFXSTREAM_ASSERT( + CreateAHBWithCheckerboard(256, 256, 64, GFXSTREAM_AHB_FORMAT_Y8Cb8Cr8_420, yuvColor1, yuvColor2)); + auto resultAhb = GFXSTREAM_ASSERT( + ScopedAHardwareBuffer::Allocate(*mGralloc, 256, 256, GFXSTREAM_AHB_FORMAT_R8G8B8A8_UNORM)); + + const RenderControlComposition composition = { + .displayId = 0, + .compositionResultColorBufferHandle = mGralloc->getHostHandle(resultAhb), + }; + const RenderControlCompositionLayer compositionLayers[2] = { + { + .colorBufferHandle = mGralloc->getHostHandle(layer1Ahb), + .composeMode = HWC2_COMPOSITION_DEVICE, + .displayFrame = + { + .left = 0, + .top = 0, + .right = 256, + .bottom = 256, + }, + .crop = + { + .left = 0, + .top = 0, + .right = static_cast(256), + .bottom = static_cast(256), + }, + .blendMode = HWC2_BLEND_MODE_NONE, + .alpha = 1.0, + .color = + { + .r = 0, + .g = 0, + .b = 0, + .a = 0, + }, + .transform = static_cast(0), + }, + { + .colorBufferHandle = mGralloc->getHostHandle(layer2Ahb), + .composeMode = HWC2_COMPOSITION_DEVICE, + .displayFrame = + { + .left = 64, + .top = 32, + .right = 128, + .bottom = 160, + }, + .crop = + { + .left = 0, + .top = 0, + .right = static_cast(256), + .bottom = static_cast(256), + }, + .blendMode = HWC2_BLEND_MODE_NONE, + .alpha = 1.0, + .color = + { + .r = 0, + .g = 0, + .b = 0, + .a = 0, + }, + .transform = HWC_TRANSFORM_ROT_90, + }, + }; + + ASSERT_THAT(mRc->rcCompose(rcDevice, &composition, 2, compositionLayers), Eq(0)); + + GFXSTREAM_ASSERT(CompareAHBWithGolden(resultAhb, "256x256_golden_rotated_yv12.png")); +} + INSTANTIATE_TEST_SUITE_P(GfxstreamEnd2EndTests, GfxstreamEnd2EndCompositionTest, ::testing::ValuesIn({ TestParams{ diff --git a/tests/end2end/gfxstream_end2end_gralloc_tests.cpp b/tests/end2end/gfxstream_end2end_gralloc_tests.cpp index 26149bef2..c4d70062f 100644 --- a/tests/end2end/gfxstream_end2end_gralloc_tests.cpp +++ b/tests/end2end/gfxstream_end2end_gralloc_tests.cpp @@ -34,6 +34,11 @@ TEST_P(GfxstreamEnd2EndGrallocTests, Allocate_YV12) { *mGralloc, 32, 32, GFXSTREAM_AHB_FORMAT_YV12)); } +TEST_P(GfxstreamEnd2EndGrallocTests, Allocate_YCbCr888420) { + auto ahb = GFXSTREAM_ASSERT(ScopedAHardwareBuffer::Allocate( + *mGralloc, 32, 32, GFXSTREAM_AHB_FORMAT_Y8Cb8Cr8_420)); +} + TEST_P(GfxstreamEnd2EndGrallocTests, AllocateTransfer_RGBA8888) { constexpr const uint32_t kWidth = 32; constexpr const uint32_t kHeight = 32; @@ -149,6 +154,82 @@ TEST_P(GfxstreamEnd2EndGrallocTests, AllocateTransfer_YV12) { } } +TEST_P(GfxstreamEnd2EndGrallocTests, AllocateTransfer_YCbCr888420) { + constexpr const uint32_t kWidth = 32; + constexpr const uint32_t kHeight = 32; + + auto ahb = GFXSTREAM_ASSERT(ScopedAHardwareBuffer::Allocate( + *mGralloc, kWidth, kHeight, GFXSTREAM_AHB_FORMAT_Y8Cb8Cr8_420)); + + const PixelR8G8B8A8 color = PixelR8G8B8A8(11, 22, 33, 44); + + uint8_t colorY; + uint8_t colorU; + uint8_t colorV; + RGBToYUV(color.r, color.g, color.b, &colorY, &colorU, &colorV); + + { + std::vector ahbPlanes = + GFXSTREAM_ASSERT(ahb.LockPlanes()); + const Gralloc::LockedPlane& yPlane = ahbPlanes[0]; + const Gralloc::LockedPlane& uPlane = ahbPlanes[1]; + const Gralloc::LockedPlane& vPlane = ahbPlanes[2]; + + for (uint32_t y = 0; y < kHeight; y++) { + for (uint32_t x = 0; x < kWidth; x++) { + uint8_t* dstY = yPlane.data + + (y * yPlane.rowStrideBytes) + + (x * yPlane.pixelStrideBytes); + *dstY = colorY; + } + } + for (uint32_t y = 0; y < kHeight / 2; y++) { + for (uint32_t x = 0; x < kWidth / 2; x++) { + uint8_t* dstU = uPlane.data + + (y * uPlane.rowStrideBytes) + + (x * uPlane.pixelStrideBytes); + uint8_t* dstV = vPlane.data + + (y * vPlane.rowStrideBytes) + + (x * vPlane.pixelStrideBytes); + *dstU = colorU; + *dstV = colorV; + } + } + + ahb.Unlock(); + } + { + std::vector ahbPlanes = + GFXSTREAM_ASSERT(ahb.LockPlanes()); + const Gralloc::LockedPlane& yPlane = ahbPlanes[0]; + const Gralloc::LockedPlane& uPlane = ahbPlanes[1]; + const Gralloc::LockedPlane& vPlane = ahbPlanes[2]; + + for (uint32_t y = 0; y < kHeight; y++) { + for (uint32_t x = 0; x < kWidth; x++) { + const uint8_t* actualY = yPlane.data + + (y * yPlane.rowStrideBytes) + + (x * yPlane.pixelStrideBytes); + ASSERT_THAT(*actualY, Eq(colorY)); + } + } + for (uint32_t y = 0; y < kHeight / 2; y++) { + for (uint32_t x = 0; x < kWidth / 2; x++) { + const uint8_t* actualU = uPlane.data + + (y * uPlane.rowStrideBytes) + + (x * uPlane.pixelStrideBytes); + const uint8_t* actualV = vPlane.data + + (y * vPlane.rowStrideBytes) + + (x * vPlane.pixelStrideBytes); + ASSERT_THAT(*actualU, Eq(colorU)); + ASSERT_THAT(*actualV, Eq(colorV)); + } + } + + ahb.Unlock(); + } +} + TEST_P(GfxstreamEnd2EndGrallocTests, AllocateTransfer_Depth32FloatStencil8) { constexpr const uint32_t kWidth = 32; constexpr const uint32_t kHeight = 32; diff --git a/tests/end2end/gfxstream_end2end_tests.cpp b/tests/end2end/gfxstream_end2end_tests.cpp index dc493bc6a..740afd67a 100644 --- a/tests/end2end/gfxstream_end2end_tests.cpp +++ b/tests/end2end/gfxstream_end2end_tests.cpp @@ -475,6 +475,13 @@ Result ScopedAHardwareBuffer::Allocate(Gralloc& gralloc, std::to_string(width)); } } + if (format == GFXSTREAM_AHB_FORMAT_Y8Cb8Cr8_420) { + if ((width % 2) != 0) { + return gfxstream::unexpected( + "Failed to allocate Y8Cb8Cr8_420 AHB with non multiple of 2 width: " + + std::to_string(width)); + } + } AHardwareBuffer* ahb = nullptr; int status = gralloc.allocate(width, height, format, -1, &ahb); diff --git a/third_party/rutabaga/BUILD.rutabaga.bazel b/third_party/rutabaga/BUILD.rutabaga.bazel index 42b796ada..6a77c2e29 100644 --- a/third_party/rutabaga/BUILD.rutabaga.bazel +++ b/third_party/rutabaga/BUILD.rutabaga.bazel @@ -1,5 +1,5 @@ -load("@rules_cc//cc:defs.bzl", "cc_library") -load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_library", "rust_static_library") +load("@rules_cc//cc:defs.bzl", "cc_library") # @unused +load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_library") package( default_visibility = ["@//:gfxstream"],