(Reland) Rename ColorBuffer to ColorBufferGl and add ColorBuffer
... which wraps ColorBufferGl and effectively ColorBufferVk
as the existing ColorBuffer code is GL specific. Moves routing
of existing Gl specific functions through prefixed 'glOp*'
functions. Potentially, ColorBuffer should just provide API
specific functions and be responsible for handling coordination
across APIs (sync'ing between Gl and Vk on read/update).
Reland needed to include aosp/2385074.
Bug: b/233939967
Test: android build
Test: cmake build
Test: cvd start --gpu_mode=gfxstream
Test: gfxstream unit tests
Change-Id: Ibe6a0a2774848b59b82f23a9f2541324a558c7e5
diff --git a/stream-servers/Android.bp b/stream-servers/Android.bp
index 2079cd4..00946af 100644
--- a/stream-servers/Android.bp
+++ b/stream-servers/Android.bp
@@ -57,6 +57,7 @@
],
srcs: [
"ChannelStream.cpp",
+ "ColorBuffer.cpp",
"DisplaySurface.cpp",
"DisplaySurfaceUser.cpp",
"Hwc2.cpp",
diff --git a/stream-servers/CMakeLists.txt b/stream-servers/CMakeLists.txt
index ead0364..864e6ba 100644
--- a/stream-servers/CMakeLists.txt
+++ b/stream-servers/CMakeLists.txt
@@ -13,6 +13,7 @@
# Stream server core
set(stream-server-core-sources
+ ColorBuffer.cpp
GfxStreamAgents.cpp
VirtioGpuTimelines.cpp
VsyncThread.cpp
diff --git a/stream-servers/ColorBuffer.cpp b/stream-servers/ColorBuffer.cpp
new file mode 100644
index 0000000..7d8cc68
--- /dev/null
+++ b/stream-servers/ColorBuffer.cpp
@@ -0,0 +1,451 @@
+// 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 "ColorBuffer.h"
+
+#include "gl/EmulationGl.h"
+#include "vulkan/VkCommonOperations.h"
+
+using android::base::ManagedDescriptor;
+using emugl::ABORT_REASON_OTHER;
+using emugl::FatalError;
+
+namespace {
+
+// ColorBufferVk natively supports YUV images. However, ColorBufferGl
+// needs to emulate YUV support by having an underlying RGBA texture
+// and adding in additional YUV<->RGBA conversions when needed. The
+// memory should not be shared between the VK YUV image and the GL RGBA
+// texture.
+bool shouldAttemptExternalMemorySharing(FrameworkFormat format) {
+ return format == FrameworkFormat::FRAMEWORK_FORMAT_GL_COMPATIBLE;
+}
+
+} // namespace
+
+ColorBuffer::ColorBuffer(HandleType handle, uint32_t width, uint32_t height, GLenum format,
+ FrameworkFormat frameworkFormat)
+ : mHandle(handle),
+ mWidth(width),
+ mHeight(height),
+ mFormat(format),
+ mFrameworkFormat(frameworkFormat) {}
+
+/*static*/
+std::shared_ptr<ColorBuffer> ColorBuffer::create(gfxstream::EmulationGl* emulationGl,
+ goldfish_vk::VkEmulation* emulationVk,
+ uint32_t width, uint32_t height, GLenum format,
+ FrameworkFormat frameworkFormat,
+ HandleType handle) {
+ std::shared_ptr<ColorBuffer> colorBuffer(
+ new ColorBuffer(handle, width, height, format, frameworkFormat));
+
+ if (emulationGl) {
+ colorBuffer->mColorBufferGl =
+ emulationGl->createColorBuffer(width, height, format, frameworkFormat, handle);
+ if (!colorBuffer->mColorBufferGl) {
+ ERR("Failed to initialize ColorBufferGl.");
+ return nullptr;
+ }
+ }
+
+ if (emulationVk && emulationVk->live) {
+ const bool vulkanOnly = colorBuffer->mColorBufferGl == nullptr;
+
+ colorBuffer->mColorBufferVk = std::make_unique<ColorBufferVk>();
+ if (!goldfish_vk::setupVkColorBuffer(width, height, format, frameworkFormat, handle,
+ vulkanOnly, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) {
+ ERR("Failed to initialize ColorBufferVk.");
+ return nullptr;
+ }
+ }
+
+ if (colorBuffer->mColorBufferGl && colorBuffer->mColorBufferVk &&
+ shouldAttemptExternalMemorySharing(frameworkFormat)) {
+ auto memoryExport = goldfish_vk::exportColorBufferMemory(handle);
+ if (memoryExport) {
+ if (colorBuffer->mColorBufferGl->importMemory(
+ std::move(memoryExport->descriptor), memoryExport->size,
+ /*dedicated=*/false, memoryExport->linearTiling)) {
+ colorBuffer->mGlAndVkAreSharingExternalMemory = true;
+ } else {
+ ERR("Failed to import memory to ColorBufferGl:%d", handle);
+ return nullptr;
+ }
+ }
+ }
+
+ return colorBuffer;
+}
+
+/*static*/
+std::shared_ptr<ColorBuffer> ColorBuffer::onLoad(gfxstream::EmulationGl* emulationGl,
+ goldfish_vk::VkEmulation*,
+ android::base::Stream* stream) {
+ const auto handle = static_cast<HandleType>(stream->getBe32());
+ const auto width = static_cast<uint32_t>(stream->getBe32());
+ const auto height = static_cast<uint32_t>(stream->getBe32());
+ const auto format = static_cast<GLenum>(stream->getBe32());
+ const auto frameworkFormat = static_cast<FrameworkFormat>(stream->getBe32());
+
+ std::shared_ptr<ColorBuffer> colorBuffer(
+ new ColorBuffer(handle, width, height, format, frameworkFormat));
+
+ if (emulationGl) {
+ colorBuffer->mColorBufferGl = emulationGl->loadColorBuffer(stream);
+ if (!colorBuffer->mColorBufferGl) {
+ ERR("Failed to load ColorBufferGl.");
+ return nullptr;
+ }
+ }
+
+ colorBuffer->mNeedRestore = true;
+
+ return colorBuffer;
+}
+
+void ColorBuffer::onSave(android::base::Stream* stream) {
+ stream->putBe32(getHndl());
+ stream->putBe32(mWidth);
+ stream->putBe32(mHeight);
+ stream->putBe32(static_cast<uint32_t>(mFormat));
+ stream->putBe32(static_cast<uint32_t>(mFrameworkFormat));
+
+ if (mColorBufferGl) {
+ mColorBufferGl->onSave(stream);
+ }
+}
+
+void ColorBuffer::restore() {
+ if (mColorBufferGl) {
+ mColorBufferGl->restore();
+ }
+}
+
+void ColorBuffer::readToBytes(int x, int y, int width, int height, GLenum pixelsFormat,
+ GLenum pixelsType, void* outPixels) {
+ touch();
+
+ if (mColorBufferVk) {
+ goldfish_vk::readColorBufferToBytes(mHandle, x, y, width, height, outPixels);
+ return;
+ }
+ if (mColorBufferGl) {
+ mColorBufferGl->readPixels(x, y, width, height, pixelsFormat, pixelsType, outPixels);
+ return;
+ }
+
+ GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "No ColorBuffer impl?";
+}
+
+void ColorBuffer::readToBytesScaled(int pixelsWidth, int pixelsHeight, GLenum pixelsFormat,
+ GLenum pixelsType, int pixelsRotation, emugl::Rect rect,
+ void* outPixels) {
+ touch();
+
+ if (mColorBufferGl) {
+ mColorBufferGl->readPixelsScaled(pixelsWidth, pixelsHeight, pixelsFormat, pixelsType,
+ pixelsRotation, rect, outPixels);
+ return;
+ }
+
+ GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "Unimplemented.";
+}
+
+void ColorBuffer::readYuvToBytes(int x, int y, int width, int height, void* outPixels,
+ uint32_t pixelsSize) {
+ touch();
+
+ if (mColorBufferVk) {
+ goldfish_vk::readColorBufferToBytes(mHandle, x, y, width, height, outPixels);
+ return;
+ }
+ if (mColorBufferGl) {
+ mColorBufferGl->readPixelsYUVCached(x, y, width, height, outPixels, pixelsSize);
+ return;
+ }
+
+ GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "No ColorBuffer impl?";
+}
+
+bool ColorBuffer::updateFromBytes(int x, int y, int width, int height,
+ FrameworkFormat frameworkFormat, GLenum pixelsFormat,
+ GLenum pixelsType, const void* pixels) {
+ touch();
+
+ if (mColorBufferVk) {
+ return goldfish_vk::updateColorBufferFromBytes(mHandle, x, y, width, height, pixels);
+ }
+ if (mColorBufferGl) {
+ mColorBufferGl->subUpdateFromFrameworkFormat(x, y, width, height, frameworkFormat,
+ pixelsFormat, pixelsType, pixels);
+ return true;
+ }
+
+ GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "No ColorBuffer impl?";
+ return false;
+}
+
+bool ColorBuffer::updateFromBytes(int x, int y, int width, int height, GLenum pixelsFormat,
+ GLenum pixelsType, const void* pixels) {
+ touch();
+
+ if (mColorBufferVk) {
+ return goldfish_vk::updateColorBufferFromBytes(mHandle, x, y, width, height, pixels);
+ }
+ if (mColorBufferGl) {
+ mColorBufferGl->subUpdate(x, y, width, height, pixelsFormat, pixelsType, pixels);
+ return true;
+ }
+
+ GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "No ColorBuffer impl?";
+ return false;
+}
+
+bool ColorBuffer::updateGlFromBytes(const void* bytes, std::size_t bytesSize) {
+ if (mColorBufferGl) {
+ touch();
+
+ return mColorBufferGl->replaceContents(bytes, bytesSize);
+ }
+
+ return true;
+}
+
+std::unique_ptr<BorrowedImageInfo> ColorBuffer::borrowForComposition(UsedApi api, bool isTarget) {
+ switch (api) {
+ case UsedApi::kGl: {
+ if (!mColorBufferGl) {
+ GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "ColorBufferGl not available.";
+ }
+ return mColorBufferGl->getBorrowedImageInfo();
+ }
+ case UsedApi::kVk: {
+ if (!mColorBufferVk) {
+ GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "ColorBufferGl not available.";
+ }
+ return goldfish_vk::borrowColorBufferForComposition(getHndl(), isTarget);
+ }
+ }
+ GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "Unimplemented";
+ return nullptr;
+}
+
+std::unique_ptr<BorrowedImageInfo> ColorBuffer::borrowForDisplay(UsedApi api) {
+ switch (api) {
+ case UsedApi::kGl: {
+ if (!mColorBufferGl) {
+ GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "ColorBufferGl not available.";
+ }
+ return mColorBufferGl->getBorrowedImageInfo();
+ }
+ case UsedApi::kVk: {
+ if (!mColorBufferVk) {
+ GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "ColorBufferGl not available.";
+ }
+ return goldfish_vk::borrowColorBufferForDisplay(getHndl());
+ }
+ }
+ GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "Unimplemented";
+ return nullptr;
+}
+
+void ColorBuffer::updateFromGl() {
+ if (!(mColorBufferGl && mColorBufferVk)) {
+ return;
+ }
+
+ if (mGlAndVkAreSharingExternalMemory) {
+ return;
+ }
+
+ std::size_t contentsSize = 0;
+ if (!mColorBufferGl->readContents(&contentsSize, nullptr)) {
+ ERR("Failed to get GL contents size for ColorBuffer:%d", mHandle);
+ return;
+ }
+
+ std::vector<uint8_t> contents(contentsSize, 0);
+
+ if (!mColorBufferGl->readContents(&contentsSize, contents.data())) {
+ ERR("Failed to get GL contents for ColorBuffer:%d", mHandle);
+ return;
+ }
+
+ if (!goldfish_vk::updateColorBufferFromBytes(mHandle, contents)) {
+ ERR("Failed to set VK contents for ColorBuffer:%d", mHandle);
+ return;
+ }
+}
+
+void ColorBuffer::updateFromVk() {
+ if (!(mColorBufferGl && mColorBufferVk)) {
+ return;
+ }
+
+ if (mGlAndVkAreSharingExternalMemory) {
+ return;
+ }
+
+ std::vector<uint8_t> contents;
+ if (!goldfish_vk::readColorBufferToBytes(mHandle, &contents)) {
+ ERR("Failed to get VK contents for ColorBuffer:%d", mHandle);
+ return;
+ }
+
+ if (contents.empty()) return;
+
+ if (!mColorBufferGl->replaceContents(contents.data(), contents.size())) {
+ ERR("Failed to set GL contents for ColorBuffer:%d", mHandle);
+ return;
+ }
+}
+
+bool ColorBuffer::glOpBlitFromCurrentReadBuffer() {
+ if (!mColorBufferGl) {
+ GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "ColorBufferGl not available.";
+ }
+
+ touch();
+
+ return mColorBufferGl->blitFromCurrentReadBuffer();
+}
+
+bool ColorBuffer::glOpBindToTexture() {
+ if (!mColorBufferGl) {
+ GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "ColorBufferGl not available.";
+ }
+
+ touch();
+
+ return mColorBufferGl->bindToTexture();
+}
+
+bool ColorBuffer::glOpBindToTexture2() {
+ if (!mColorBufferGl) {
+ GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "ColorBufferGl not available.";
+ }
+
+ return mColorBufferGl->bindToTexture2();
+}
+
+bool ColorBuffer::glOpBindToRenderbuffer() {
+ if (!mColorBufferGl) {
+ GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "ColorBufferGl not available.";
+ }
+
+ touch();
+
+ return mColorBufferGl->bindToRenderbuffer();
+}
+
+GLuint ColorBuffer::glOpGetTexture() {
+ if (!mColorBufferGl) {
+ GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "ColorBufferGl not available.";
+ }
+
+ touch();
+
+ return mColorBufferGl->getTexture();
+}
+
+void ColorBuffer::glOpReadback(unsigned char* img, bool readbackBgra) {
+ if (!mColorBufferGl) {
+ GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "ColorBufferGl not available.";
+ }
+
+ touch();
+
+ return mColorBufferGl->readback(img, readbackBgra);
+}
+
+void ColorBuffer::glOpReadbackAsync(GLuint buffer, bool readbackBgra) {
+ if (!mColorBufferGl) {
+ GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "ColorBufferGl not available.";
+ }
+
+ touch();
+
+ mColorBufferGl->readbackAsync(buffer, readbackBgra);
+}
+
+bool ColorBuffer::glOpImportEglImage(void* image, bool preserveContent) {
+ if (!mColorBufferGl) {
+ GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "ColorBufferGl not available.";
+ }
+
+ return mColorBufferGl->importEglImage(image, preserveContent);
+}
+
+bool ColorBuffer::glOpImportEglNativePixmap(void* pixmap, bool preserveContent) {
+ if (!mColorBufferGl) {
+ GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "ColorBufferGl not available.";
+ }
+
+ return mColorBufferGl->importEglNativePixmap(pixmap, preserveContent);
+}
+
+void ColorBuffer::glOpSwapYuvTexturesAndUpdate(GLenum format, GLenum type,
+ FrameworkFormat frameworkFormat, GLuint* textures) {
+ if (!mColorBufferGl) {
+ GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "ColorBufferGl not available.";
+ }
+
+ mColorBufferGl->swapYUVTextures(frameworkFormat, textures);
+
+ // This makes ColorBufferGl regenerate the RGBA texture using
+ // YUVConverter::drawConvert() with the updated YUV textures.
+ mColorBufferGl->subUpdate(0, 0, mWidth, mHeight, format, type, nullptr);
+
+ updateFromGl();
+}
+
+bool ColorBuffer::glOpReadContents(size_t* outNumBytes, void* outContents) {
+ if (!mColorBufferGl) {
+ GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "ColorBufferGl not available.";
+ }
+
+ return mColorBufferGl->readContents(outNumBytes, outContents);
+}
+
+bool ColorBuffer::glOpReplaceContents(size_t numBytes, const void* contents) {
+ if (mColorBufferGl) {
+ return mColorBufferGl->replaceContents(contents, numBytes);
+ }
+ return false;
+}
+
+bool ColorBuffer::glOpIsFastBlitSupported() const {
+ if (!mColorBufferGl) {
+ GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "ColorBufferGl not available.";
+ }
+
+ return mColorBufferGl->isFastBlitSupported();
+}
+
+void ColorBuffer::glOpPostLayer(const ComposeLayer& l, int frameWidth, int frameHeight) {
+ if (!mColorBufferGl) {
+ GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "ColorBufferGl not available.";
+ }
+
+ mColorBufferGl->postLayer(l, frameWidth, frameHeight);
+}
+
+void ColorBuffer::glOpPostViewportScaledWithOverlay(float rotation, float dx, float dy) {
+ if (!mColorBufferGl) {
+ GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "ColorBufferGl not available.";
+ }
+
+ mColorBufferGl->postViewportScaledWithOverlay(rotation, dx, dy);
+}
diff --git a/stream-servers/ColorBuffer.h b/stream-servers/ColorBuffer.h
new file mode 100644
index 0000000..09c7f6c
--- /dev/null
+++ b/stream-servers/ColorBuffer.h
@@ -0,0 +1,133 @@
+// 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 <memory>
+
+#include "BorrowedImage.h"
+#include "FrameworkFormats.h"
+#include "Handle.h"
+#include "Hwc2.h"
+#include "aemu/base/files/Stream.h"
+#include "gl/ColorBufferGl.h"
+#include "render-utils/Renderer.h"
+#include "snapshot/LazySnapshotObj.h"
+
+namespace gfxstream {
+class EmulationGl;
+} // namespace gfxstream
+namespace goldfish_vk {
+struct VkEmulation;
+} // namespace goldfish_vk
+
+class ColorBuffer : public android::snapshot::LazySnapshotObj<ColorBuffer> {
+ public:
+ static std::shared_ptr<ColorBuffer> create(gfxstream::EmulationGl* emulationGl,
+ goldfish_vk::VkEmulation* emulationVk,
+ uint32_t width, uint32_t height, GLenum format,
+ FrameworkFormat frameworkFormat, HandleType handle);
+
+ static std::shared_ptr<ColorBuffer> onLoad(gfxstream::EmulationGl* emulationGl,
+ goldfish_vk::VkEmulation* emulationVk,
+ android::base::Stream* stream);
+ void onSave(android::base::Stream* stream);
+ void restore();
+
+ HandleType getHndl() const { return mHandle; }
+ uint32_t getWidth() const { return mWidth; }
+ uint32_t getHeight() const { return mHeight; }
+ GLenum getFormat() const { return mFormat; }
+ FrameworkFormat getFrameworkFormat() const { return mFrameworkFormat; }
+
+ void readToBytes(int x, int y, int width, int height, GLenum pixelsFormat, GLenum pixelsType,
+ void* outPixels);
+ void readToBytesScaled(int pixelsWidth, int pixelsHeight, GLenum pixelsFormat,
+ GLenum pixelsType, int pixelsRotation, emugl::Rect rect,
+ void* outPixels);
+ void readYuvToBytes(int x, int y, int width, int height, void* outPixels, uint32_t pixelsSize);
+
+ bool updateFromBytes(int x, int y, int width, int height, GLenum pixelsFormat,
+ GLenum pixelsType, const void* pixels);
+ bool updateFromBytes(int x, int y, int width, int height, FrameworkFormat frameworkFormat,
+ GLenum pixelsFormat, GLenum pixelsType, const void* pixels);
+ bool updateGlFromBytes(const void* bytes, std::size_t bytesSize);
+
+ enum class UsedApi {
+ kGl,
+ kVk,
+ };
+ std::unique_ptr<BorrowedImageInfo> borrowForComposition(UsedApi api, bool isTarget);
+ std::unique_ptr<BorrowedImageInfo> borrowForDisplay(UsedApi api);
+
+ void updateFromGl();
+ void updateFromVk();
+
+ GLuint glOpGetTexture();
+ bool glOpBlitFromCurrentReadBuffer();
+ bool glOpBindToTexture();
+ bool glOpBindToTexture2();
+ bool glOpBindToRenderbuffer();
+ void glOpReadback(unsigned char* img, bool readbackBgra);
+ void glOpReadbackAsync(GLuint buffer, bool readbackBgra);
+ bool glOpImportEglImage(void* image, bool preserveContent);
+ bool glOpImportEglNativePixmap(void* pixmap, bool preserveContent);
+ void glOpSwapYuvTexturesAndUpdate(GLenum format, GLenum type, FrameworkFormat frameworkFormat,
+ GLuint* textures);
+ bool glOpReadContents(size_t* outNumBytes, void* outContents);
+ bool glOpReplaceContents(size_t numBytes, const void* contents);
+ bool glOpIsFastBlitSupported() const;
+ void glOpPostLayer(const ComposeLayer& l, int frameWidth, int frameHeight);
+ void glOpPostViewportScaledWithOverlay(float rotation, float dx, float dy);
+
+ private:
+ ColorBuffer(HandleType, uint32_t width, uint32_t height, GLenum format,
+ FrameworkFormat frameworkFormat);
+
+ const HandleType mHandle;
+ const uint32_t mWidth;
+ const uint32_t mHeight;
+ const GLenum mFormat;
+ const FrameworkFormat mFrameworkFormat;
+
+ // If GL emulation is enabled.
+ std::unique_ptr<gfxstream::ColorBufferGl> mColorBufferGl;
+
+ // If Vk emulation is enabled.
+ struct ColorBufferVk {
+ bool thisIsAPlaceHolder = true;
+ };
+ std::unique_ptr<ColorBufferVk> mColorBufferVk;
+
+ bool mGlAndVkAreSharingExternalMemory = false;
+};
+
+typedef std::shared_ptr<ColorBuffer> 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;
+};
+
+typedef std::unordered_map<HandleType, ColorBufferRef> ColorBufferMap;
+typedef std::unordered_multiset<HandleType> ColorBufferSet;
\ No newline at end of file
diff --git a/stream-servers/FrameBuffer.cpp b/stream-servers/FrameBuffer.cpp
index 04b344f..2126e62 100644
--- a/stream-servers/FrameBuffer.cpp
+++ b/stream-servers/FrameBuffer.cpp
@@ -229,6 +229,7 @@
if (!vkEmu) {
ERR("Failed to initialize global Vulkan emulation. Disable the Vulkan support.");
}
+ fb->m_emulationVk = vkEmu;
}
if (vkEmu) {
fb->m_vulkanEnabled = true;
@@ -443,22 +444,6 @@
}
}
-void FrameBuffer::setColorBufferInUse(
- uint32_t colorBufferHandle,
- bool inUse) {
-
- AutoLock mutex(m_lock);
-
- ColorBufferPtr colorBuffer = findColorBuffer(colorBufferHandle);
- if (!colorBuffer) {
- // bad colorbuffer handle
- ERR("FB: setColorBufferInUse cb handle %#x not found", colorBufferHandle);
- return;
- }
-
- colorBuffer->setInUse(inUse);
-}
-
void FrameBuffer::fillGLESUsages(android_studio::EmulatorGLESUsages* usages) {
if (s_egl.eglFillUsages) {
s_egl.eglFillUsages(usages);
@@ -662,11 +647,10 @@
res.wait();
if (postOnlyOnMainThread && (PostCmd::Screenshot == post.cmd) &&
emugl::get_emugl_window_operations().isRunningInUiThread()) {
- post.cb->readPixelsScaled(post.screenshot.screenwidth,
- post.screenshot.screenheight,
- post.screenshot.format, post.screenshot.type,
- post.screenshot.rotation,
- post.screenshot.pixels, post.screenshot.rect);
+ post.cb->readToBytesScaled(post.screenshot.screenwidth, post.screenshot.screenheight,
+ post.screenshot.format, post.screenshot.type,
+ post.screenshot.rotation, post.screenshot.rect,
+ post.screenshot.pixels);
} else {
std::future<void> completeFuture =
m_postThread.enqueue(Post(std::move(post)));
@@ -1071,21 +1055,8 @@
GLenum p_internalFormat,
FrameworkFormat p_frameworkFormat,
HandleType handle) {
- EGLDisplay display = EGL_NO_DISPLAY;
- ContextHelper* contextHelper = nullptr;
- TextureDraw* textureDraw = nullptr;
- bool isFastBlitSupported = false;
- if (m_emulationGl) {
- display = getDisplay();
- contextHelper = getPbufferSurfaceContextHelper();
- textureDraw = getTextureDraw();
- isFastBlitSupported = this->isFastBlitSupported();
- }
-
- ColorBufferPtr cb(ColorBuffer::create(display, p_width, p_height,
- p_internalFormat, p_frameworkFormat,
- handle, contextHelper, textureDraw,
- isFastBlitSupported, m_guestUsesAngle));
+ ColorBufferPtr cb = ColorBuffer::create(m_emulationGl.get(), m_emulationVk, p_width, p_height,
+ p_internalFormat, p_frameworkFormat, handle);
if (cb.get() == nullptr) {
GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
<< "Failed to create ColorBuffer:" << handle << " format:" << p_internalFormat
@@ -1093,27 +1064,6 @@
<< " height:" << p_height;
}
- if (m_vulkanEnabled) {
- if (!goldfish_vk::setupVkColorBuffer(
- p_width, p_height, p_internalFormat, p_frameworkFormat, handle,
- /*vulkanOnly=*/m_guestUsesAngle, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) {
- GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
- << "Failed to create color buffer."
- << " format:" << p_internalFormat << " width:" << p_width << " height:" << p_height;
- return 0;
- }
-
- auto memoryExport = goldfish_vk::exportColorBufferMemory(handle);
- if (memoryExport) {
- if (!cb->importMemory(std::move(memoryExport->descriptor), memoryExport->size,
- /*dedicated=*/false, memoryExport->linearTiling,
- /*vulkanOnly*/false)) {
- ERR("Failed to import memory to ColorBuffer:%d", handle);
- return 0;
- }
- }
- }
-
assert(m_colorbuffers.count(handle) == 0);
// When guest feature flag RefCountPipe is on, no reference counting is
// needed. We only memoize the mapping from handle to ColorBuffer.
@@ -1912,19 +1862,8 @@
buffer->read(offset, size, bytes);
}
-void FrameBuffer::readColorBuffer(HandleType p_colorbuffer,
- int x,
- int y,
- int width,
- int height,
- GLenum format,
- GLenum type,
- void* pixels) {
- if (m_guestUsesAngle) {
- goldfish_vk::readColorBufferToBytes(p_colorbuffer, x, y, width, height, pixels);
- return;
- }
-
+void FrameBuffer::readColorBuffer(HandleType p_colorbuffer, int x, int y, int width, int height,
+ GLenum format, GLenum type, void* pixels) {
AutoLock mutex(m_lock);
ColorBufferPtr colorBuffer = findColorBuffer(p_colorbuffer);
@@ -1933,21 +1872,11 @@
return;
}
- colorBuffer->readPixels(x, y, width, height, format, type, pixels);
+ colorBuffer->readToBytes(x, y, width, height, format, type, pixels);
}
-void FrameBuffer::readColorBufferYUV(HandleType p_colorbuffer,
- int x,
- int y,
- int width,
- int height,
- void* pixels,
- uint32_t pixels_size) {
- if (m_guestUsesAngle) {
- goldfish_vk::readColorBufferToBytes(p_colorbuffer, x, y, width, height, pixels);
- return;
- }
-
+void FrameBuffer::readColorBufferYUV(HandleType p_colorbuffer, int x, int y, int width, int height,
+ void* pixels, uint32_t pixels_size) {
AutoLock mutex(m_lock);
ColorBufferPtr colorBuffer = findColorBuffer(p_colorbuffer);
@@ -1956,7 +1885,7 @@
return;
}
- colorBuffer->readPixelsYUVCached(x, y, width, height, pixels, pixels_size);
+ colorBuffer->readYuvToBytes(x, y, width, height, pixels, pixels_size);
}
void FrameBuffer::createYUVTextures(uint32_t type,
@@ -2040,11 +1969,9 @@
// bad colorbuffer handle
return;
}
- colorBuffer->swapYUVTextures(texture_type, textures);
+ colorBuffer->glOpSwapYuvTexturesAndUpdate(
+ format, type, static_cast<FrameworkFormat>(texture_type), textures);
}
-
- updateColorBuffer(p_colorbuffer, x, y, width, height, format, type,
- nullptr);
}
bool FrameBuffer::updateBuffer(HandleType p_buffer, uint64_t offset, uint64_t size, void* bytes) {
@@ -2077,10 +2004,6 @@
return false;
}
- if (m_guestUsesAngle) {
- return goldfish_vk::updateColorBufferFromBytes(p_colorbuffer, x, y, width, height, pixels);
- }
-
AutoLock mutex(m_lock);
ColorBufferPtr colorBuffer = findColorBuffer(p_colorbuffer);
@@ -2089,7 +2012,7 @@
return false;
}
- colorBuffer->subUpdate(x, y, width, height, format, type, pixels);
+ colorBuffer->updateFromBytes(x, y, width, height, format, type, pixels);
return true;
}
@@ -2110,9 +2033,7 @@
return false;
}
- (*c).second.cb->subUpdateFromFrameworkFormat(x, y, width, height, fwkFormat, format, type,
- pixels);
-
+ (*c).second.cb->updateFromBytes(x, y, width, height, fwkFormat, format, type, pixels);
return true;
}
@@ -2126,7 +2047,7 @@
return false;
}
- return colorBuffer->replaceContents(pixels, numBytes);
+ return colorBuffer->glOpReplaceContents(numBytes, pixels);
}
bool FrameBuffer::readColorBufferContents(
@@ -2140,7 +2061,7 @@
return false;
}
- return colorBuffer->readContents(numBytes, pixels);
+ return colorBuffer->glOpReadContents(numBytes, pixels);
}
bool FrameBuffer::getColorBufferInfo(
@@ -2157,7 +2078,7 @@
*width = colorBuffer->getWidth();
*height = colorBuffer->getHeight();
- *internalformat = colorBuffer->getInternalFormat();
+ *internalformat = colorBuffer->getFormat();
if (frameworkFormat) {
*frameworkFormat = colorBuffer->getFrameworkFormat();
}
@@ -2188,7 +2109,7 @@
return false;
}
- return colorBuffer->bindToTexture();
+ return colorBuffer->glOpBindToTexture();
}
bool FrameBuffer::bindColorBufferToTexture2(HandleType p_colorbuffer) {
@@ -2205,7 +2126,7 @@
return false;
}
- return colorBuffer->bindToTexture2();
+ return colorBuffer->glOpBindToTexture2();
}
bool FrameBuffer::bindColorBufferToRenderbuffer(HandleType p_colorbuffer) {
@@ -2217,7 +2138,7 @@
return false;
}
- return colorBuffer->bindToRenderbuffer();
+ return colorBuffer->glOpBindToRenderbuffer();
}
bool FrameBuffer::bindContext(HandleType p_context,
@@ -2580,7 +2501,7 @@
doPostCallback(iter.second.img, iter.first);
}
} else {
- cb->readback(iter.second.img, iter.second.readBgra);
+ cb->glOpReadback(iter.second.img, iter.second.readBgra);
doPostCallback(iter.second.img, iter.first);
}
}
@@ -3194,8 +3115,7 @@
m_guestManagedColorBufferLifetime = stream->getByte();
loadCollection(
stream, &m_colorbuffers, [this, now](Stream* stream) -> ColorBufferMap::value_type {
- ColorBufferPtr cb(ColorBuffer::onLoad(stream, getDisplay(), getPbufferSurfaceContextHelper(),
- getTextureDraw(), isFastBlitSupported()));
+ ColorBufferPtr cb = ColorBuffer::onLoad(m_emulationGl.get(), m_emulationVk, stream);
const HandleType handle = cb->getHndl();
const unsigned refCount = stream->getBe32();
const bool opened = stream->getByte();
@@ -3484,9 +3404,9 @@
switch (type) {
case RESOURCE_TYPE_EGL_NATIVE_PIXMAP:
- return colorBuffer->importEglNativePixmap(resource, preserveContent);
+ return colorBuffer->glOpImportEglNativePixmap(resource, preserveContent);
case RESOURCE_TYPE_EGL_IMAGE:
- return colorBuffer->importEglImage(resource, preserveContent);
+ return colorBuffer->glOpImportEglImage(resource, preserveContent);
default:
ERR("Error: unsupported resource type: %u", type);
return false;
@@ -3531,30 +3451,25 @@
std::unique_ptr<BorrowedImageInfo> FrameBuffer::borrowColorBufferForComposition(
uint32_t colorBufferHandle, bool colorBufferIsTarget) {
- if (m_useVulkanComposition) {
- return goldfish_vk::borrowColorBufferForComposition(colorBufferHandle, colorBufferIsTarget);
- }
-
ColorBufferPtr colorBufferPtr = findColorBuffer(colorBufferHandle);
if (!colorBufferPtr) {
ERR("Failed to get borrowed image info for ColorBuffer:%d", colorBufferHandle);
return nullptr;
}
- return colorBufferPtr->getBorrowedImageInfo();
+
+ const auto api = m_useVulkanComposition ? ColorBuffer::UsedApi::kVk : ColorBuffer::UsedApi::kGl;
+ return colorBufferPtr->borrowForComposition(api, colorBufferIsTarget);
}
std::unique_ptr<BorrowedImageInfo> FrameBuffer::borrowColorBufferForDisplay(
- uint32_t colorBufferHandle) {
- if (m_useVulkanComposition) {
- return goldfish_vk::borrowColorBufferForDisplay(colorBufferHandle);
- }
-
+ uint32_t colorBufferHandle) {
ColorBufferPtr colorBufferPtr = findColorBuffer(colorBufferHandle);
if (!colorBufferPtr) {
ERR("Failed to get borrowed image info for ColorBuffer:%d", colorBufferHandle);
return nullptr;
}
- return colorBufferPtr->getBorrowedImageInfo();
+ const auto api = m_useVulkanComposition ? ColorBuffer::UsedApi::kVk : ColorBuffer::UsedApi::kGl;
+ return colorBufferPtr->borrowForDisplay(api);
}
gfxstream::EmulationGl& FrameBuffer::getEmulationGl() {
@@ -3770,30 +3685,7 @@
ERR("Failed to find ColorBuffer:%d", colorBufferHandle);
return;
}
-
- // TODO(b/233939967): move the below into the generic ColorBuffer.
-
- if (!goldfish_vk::colorBufferNeedsUpdateBetweenGlAndVk(colorBufferHandle)) {
- return;
- }
-
- std::size_t contentsSize = 0;
- if (!colorBuffer->readContents(&contentsSize, nullptr)) {
- ERR("Failed to get GL contents size for ColorBuffer:%d", colorBufferHandle);
- return;
- }
-
- std::vector<uint8_t> contents(contentsSize, 0);
-
- if (!colorBuffer->readContents(&contentsSize, contents.data())) {
- ERR("Failed to get GL contents for ColorBuffer:%d", colorBufferHandle);
- return;
- }
-
- if (!goldfish_vk::updateColorBufferFromBytes(colorBufferHandle, contents)) {
- ERR("Failed to set VK contents for ColorBuffer:%d", colorBufferHandle);
- return;
- }
+ colorBuffer->updateFromGl();
}
void FrameBuffer::updateColorBufferFromVk(HandleType colorBufferHandle) {
@@ -3804,23 +3696,5 @@
ERR("Failed to find ColorBuffer:%d", colorBufferHandle);
return;
}
-
- // TODO(b/233939967): move the below into the generic ColorBuffer.
-
- if (!goldfish_vk::colorBufferNeedsUpdateBetweenGlAndVk(colorBufferHandle)) {
- return;
- }
-
- std::vector<uint8_t> contents;
- if (!goldfish_vk::readColorBufferToBytes(colorBufferHandle, &contents)) {
- ERR("Failed to get VK contents for ColorBuffer:%d", colorBufferHandle);
- return;
- }
-
- if (contents.empty()) return;
-
- if (!colorBuffer->replaceContents(contents.data(), contents.size())) {
- ERR("Failed to set GL contents for ColorBuffer:%d", colorBufferHandle);
- return;
- }
+ colorBuffer->updateFromVk();
}
diff --git a/stream-servers/FrameBuffer.h b/stream-servers/FrameBuffer.h
index 3799295..af83273 100644
--- a/stream-servers/FrameBuffer.h
+++ b/stream-servers/FrameBuffer.h
@@ -557,7 +557,6 @@
bool isVulkanInteropSupported() const { return m_vulkanInteropSupported; }
bool isVulkanEnabled() const { return m_vulkanEnabled; }
- void setColorBufferInUse(uint32_t colorBufferHandle, bool inUse);
// Fill GLES usage protobuf
void fillGLESUsages(android_studio::EmulatorGLESUsages*);
@@ -855,6 +854,7 @@
Compositor* m_compositor = nullptr;
bool m_useVulkanComposition = false;
+ goldfish_vk::VkEmulation* m_emulationVk = nullptr;
// The implementation for Vulkan native swapchain. Only initialized when useVulkan is set when
// calling FrameBuffer::initialize(). DisplayVk is actually owned by VkEmulation.
DisplayVk *m_displayVk = nullptr;
diff --git a/stream-servers/PostWorker.cpp b/stream-servers/PostWorker.cpp
index 58bc5ec..213cd96 100644
--- a/stream-servers/PostWorker.cpp
+++ b/stream-servers/PostWorker.cpp
@@ -19,10 +19,10 @@
#include <chrono>
+#include "ColorBuffer.h"
#include "FrameBuffer.h"
#include "RenderThreadInfo.h"
#include "aemu/base/Tracing.h"
-#include "gl/ColorBufferGl.h"
#include "gl/DisplayGl.h"
#include "host-common/GfxstreamFatalError.h"
#include "host-common/logging.h"
@@ -332,8 +332,7 @@
GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) <<
"Screenshot not supported with native Vulkan swapchain enabled.";
}
- cb->readPixelsScaled(
- width, height, format, type, rotation, pixels, rect);
+ cb->readToBytesScaled(width, height, format, type, rotation, rect, pixels);
}
void PostWorker::block(std::promise<void> scheduledSignal, std::future<void> continueSignal) {
diff --git a/stream-servers/gl/ColorBufferGl.cpp b/stream-servers/gl/ColorBufferGl.cpp
index dc81841..e12cab9 100644
--- a/stream-servers/gl/ColorBufferGl.cpp
+++ b/stream-servers/gl/ColorBufferGl.cpp
@@ -40,6 +40,7 @@
using gfxstream::GLESApi_CM;
using gfxstream::GLESApi_2;
+namespace gfxstream {
namespace {
// Lazily create and bind a framebuffer object to the current host context.
@@ -65,7 +66,7 @@
#if DEBUG_CB_FBO
GLenum status = s_gles2.glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE_OES) {
- ERR("ColorBuffer::bindFbo: FBO not complete: %#x\n", status);
+ ERR("ColorBufferGl::bindFbo: FBO not complete: %#x\n", status);
s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, 0);
s_gles2.glDeleteFramebuffers(1, fbo);
*fbo = 0;
@@ -211,16 +212,12 @@
}
// static
-ColorBuffer* ColorBuffer::create(EGLDisplay p_display,
- int p_width,
- int p_height,
- GLint p_internalFormat,
- FrameworkFormat p_frameworkFormat,
- HandleType hndl,
- ContextHelper* helper,
- TextureDraw* textureDraw,
- bool fastBlitSupported,
- bool vulkanOnly) {
+std::unique_ptr<ColorBufferGl> ColorBufferGl::create(EGLDisplay p_display, int p_width,
+ int p_height, GLint p_internalFormat,
+ FrameworkFormat p_frameworkFormat,
+ HandleType hndl, ContextHelper* helper,
+ TextureDraw* textureDraw,
+ bool fastBlitSupported) {
GLenum texFormat = 0;
GLenum pixelType = GL_UNSIGNED_BYTE;
int bytesPerPixel = 4;
@@ -230,17 +227,15 @@
if (!sGetFormatParameters(&p_internalFormat, &texFormat, &pixelType,
&bytesPerPixel, &p_sizedInternalFormat,
&isBlob)) {
- fprintf(stderr, "ColorBuffer::create invalid format 0x%x\n",
- p_internalFormat);
- return NULL;
+ fprintf(stderr, "ColorBufferGl::create invalid format 0x%x\n", p_internalFormat);
+ return nullptr;
}
const unsigned long bufsize = ((unsigned long)bytesPerPixel) * p_width
* p_height;
// This constructor is private, so std::make_unique can't be used.
- std::unique_ptr<ColorBuffer> cb{new ColorBuffer(p_display, hndl, helper, textureDraw)};
- cb->m_width = p_width;
- cb->m_height = p_height;
+ std::unique_ptr<ColorBufferGl> cb{
+ new ColorBufferGl(p_display, hndl, p_width, p_height, helper, textureDraw)};
cb->m_internalFormat = p_internalFormat;
cb->m_sizedInternalFormat = p_sizedInternalFormat;
cb->m_format = texFormat;
@@ -248,18 +243,13 @@
cb->m_frameworkFormat = p_frameworkFormat;
cb->m_fastBlitSupported = fastBlitSupported;
cb->m_numBytes = (size_t)bufsize;
- cb->m_vulkanOnly = vulkanOnly;
-
- if (vulkanOnly) {
- return cb.release();
- }
RecursiveScopedContextBind context(helper);
if (!context.isOk()) {
- return NULL;
+ return nullptr;
}
- GL_SCOPED_DEBUG_GROUP("ColorBuffer::create(handle:%d)", hndl);
+ GL_SCOPED_DEBUG_GROUP("ColorBufferGl::create(handle:%d)", hndl);
GLint prevUnpackAlignment;
s_gles2.glGetIntegerv(GL_UNPACK_ALIGNMENT, &prevUnpackAlignment);
@@ -330,18 +320,19 @@
s_gles2.glPixelStorei(GL_UNPACK_ALIGNMENT, prevUnpackAlignment);
s_gles2.glFinish();
- return cb.release();
+ return cb;
}
-ColorBuffer::ColorBuffer(EGLDisplay display, HandleType hndl, ContextHelper* helper,
- TextureDraw* textureDraw)
- : m_display(display), m_helper(helper), m_textureDraw(textureDraw), mHndl(hndl) {}
+ColorBufferGl::ColorBufferGl(EGLDisplay display, HandleType hndl, GLuint width, GLuint height,
+ ContextHelper* helper, TextureDraw* textureDraw)
+ : m_width(width),
+ m_height(height),
+ m_display(display),
+ m_helper(helper),
+ m_textureDraw(textureDraw),
+ mHndl(hndl) {}
-ColorBuffer::~ColorBuffer() {
- if (m_vulkanOnly) {
- return;
- }
-
+ColorBufferGl::~ColorBufferGl() {
RecursiveScopedContextBind context(m_helper);
if (m_blitEGLImage) {
@@ -375,22 +366,18 @@
delete m_resizer;
}
-void ColorBuffer::readPixels(int x,
- int y,
- int width,
- int height,
- GLenum p_format,
- GLenum p_type,
- void* pixels) {
+void ColorBufferGl::readPixels(int x, int y, int width, int height, GLenum p_format, GLenum p_type,
+ void* pixels) {
RecursiveScopedContextBind context(m_helper);
if (!context.isOk()) {
return;
}
- GL_SCOPED_DEBUG_GROUP("ColorBuffer::readPixels(handle:%d fbo:%d tex:%d)", mHndl, m_fbo, m_tex);
+ GL_SCOPED_DEBUG_GROUP("ColorBufferGl::readPixels(handle:%d fbo:%d tex:%d)", mHndl, m_fbo,
+ m_tex);
p_format = sGetUnsizedColorBufferFormat(p_format);
- touch();
+
waitSync();
if (bindFbo(&m_fbo, m_tex, m_needFboReattach)) {
@@ -404,8 +391,8 @@
}
}
-void ColorBuffer::readPixelsScaled(int width, int height, GLenum p_format, GLenum p_type,
- int rotation, void* pixels, emugl::Rect rect) {
+void ColorBufferGl::readPixelsScaled(int width, int height, GLenum p_format, GLenum p_type,
+ int rotation, emugl::Rect rect, void* pixels) {
RecursiveScopedContextBind context(m_helper);
if (!context.isOk()) {
return;
@@ -421,7 +408,7 @@
return;
}
p_format = sGetUnsizedColorBufferFormat(p_format);
- touch();
+
waitSync();
GLuint tex = m_resizer->update(m_tex, width, height, rotation);
if (bindFbo(&m_scaleRotationFbo, tex, m_needFboReattach)) {
@@ -466,18 +453,13 @@
}
}
-void ColorBuffer::readPixelsYUVCached(int x,
- int y,
- int width,
- int height,
- void* pixels,
- uint32_t pixels_size) {
+void ColorBufferGl::readPixelsYUVCached(int x, int y, int width, int height, void* pixels,
+ uint32_t pixels_size) {
RecursiveScopedContextBind context(m_helper);
if (!context.isOk()) {
return;
}
- touch();
waitSync();
#if DEBUG_CB_FBO
@@ -487,17 +469,12 @@
assert(m_yuv_converter.get());
#endif
- if (!m_vulkanOnly) {
- m_yuv_converter->readPixels((uint8_t*)pixels, pixels_size);
- } else {
- GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) <<
- "Unexpected function call when m_vulkanOnly";
- }
+ m_yuv_converter->readPixels((uint8_t*)pixels, pixels_size);
return;
}
-void ColorBuffer::reformat(GLint internalformat, GLenum type) {
+void ColorBufferGl::reformat(GLint internalformat, GLenum type) {
GLenum texFormat = internalformat;
GLenum pixelType = GL_UNSIGNED_BYTE;
GLint sizedInternalFormat = GL_RGBA8;
@@ -559,14 +536,9 @@
m_numBytes = bpp * m_width * m_height;
}
-void ColorBuffer::swapYUVTextures(uint32_t type, uint32_t* textures) {
- if (type == FRAMEWORK_FORMAT_NV12) {
- if (!m_vulkanOnly) {
- m_yuv_converter->swapTextures(type, textures);
- } else {
- GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
- << "Unexpected function call when m_vulkanOnly";
- }
+void ColorBufferGl::swapYUVTextures(FrameworkFormat type, uint32_t* textures) {
+ if (type == FrameworkFormat::FRAMEWORK_FORMAT_NV12) {
+ m_yuv_converter->swapTextures(type, textures);
} else {
fprintf(stderr,
"%s: ERROR: format other than NV12 is not supported: 0x%x\n",
@@ -574,31 +546,21 @@
}
}
-void ColorBuffer::subUpdate(int x,
- int y,
- int width,
- int height,
- GLenum p_format,
- GLenum p_type,
- void* pixels) {
- if (m_vulkanOnly) {
- return;
- }
+void ColorBufferGl::subUpdate(int x, int y, int width, int height, GLenum p_format, GLenum p_type,
+ const void* pixels) {
subUpdateFromFrameworkFormat(x, y, width, height, m_frameworkFormat, p_format, p_type, pixels);
}
-void ColorBuffer::subUpdateFromFrameworkFormat(int x, int y, int width, int height,
- FrameworkFormat fwkFormat, GLenum p_format,
- GLenum p_type, void* pixels) {
+void ColorBufferGl::subUpdateFromFrameworkFormat(int x, int y, int width, int height,
+ FrameworkFormat fwkFormat, GLenum p_format,
+ GLenum p_type, const void* pixels) {
const GLenum p_unsizedFormat = sGetUnsizedColorBufferFormat(p_format);
RecursiveScopedContextBind context(m_helper);
if (!context.isOk()) {
return;
}
- GL_SCOPED_DEBUG_GROUP("ColorBuffer::subUpdate(handle:%d fbo:%d tex:%d)", mHndl, m_fbo, m_tex);
-
- touch();
+ GL_SCOPED_DEBUG_GROUP("ColorBufferGl::subUpdate(handle:%d fbo:%d tex:%d)", mHndl, m_fbo, m_tex);
if (m_needFormatCheck) {
if (p_type != m_type || p_format != m_format) {
@@ -633,7 +595,7 @@
}
}
-bool ColorBuffer::replaceContents(const void* newContents, size_t numBytes) {
+bool ColorBufferGl::replaceContents(const void* newContents, size_t numBytes) {
if (m_vulkanOnly) {
return false;
}
@@ -656,8 +618,6 @@
return false;
}
- touch();
-
s_gles2.glBindTexture(GL_TEXTURE_2D, m_tex);
s_gles2.glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
s_gles2.glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_width, m_height, m_format,
@@ -671,7 +631,7 @@
return true;
}
-bool ColorBuffer::readContents(size_t* numBytes, void* pixels) {
+bool ColorBufferGl::readContents(size_t* numBytes, void* pixels) {
if (m_yuv_converter) {
// common code path for vk & gles
*numBytes = m_yuv_converter->getDataSize();
@@ -691,7 +651,7 @@
}
}
-bool ColorBuffer::blitFromCurrentReadBuffer() {
+bool ColorBufferGl::blitFromCurrentReadBuffer() {
RenderThreadInfoGl* const tInfo = RenderThreadInfoGl::get();
if (!tInfo) {
GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
@@ -703,8 +663,6 @@
return false;
}
- touch();
-
if (m_fastBlitSupported) {
s_egl.eglBlitFromCurrentReadBufferANDROID(m_display, m_eglImage);
m_sync = (GLsync)s_egl.eglSetImageFenceANDROID(m_display, m_eglImage);
@@ -855,7 +813,7 @@
return true;
}
-bool ColorBuffer::bindToTexture() {
+bool ColorBufferGl::bindToTexture() {
if (!m_eglImage) {
return false;
}
@@ -869,7 +827,6 @@
if (!tInfo->currContext.get()) {
return false;
}
- touch();
if (tInfo->currContext->clientVersion() > GLESApi_CM) {
s_gles2.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, m_eglImage);
@@ -879,7 +836,7 @@
return true;
}
-bool ColorBuffer::bindToTexture2() {
+bool ColorBufferGl::bindToTexture2() {
if (!m_eglImage) {
return false;
}
@@ -888,7 +845,7 @@
return true;
}
-bool ColorBuffer::bindToRenderbuffer() {
+bool ColorBufferGl::bindToRenderbuffer() {
if (!m_eglImage) {
return false;
}
@@ -902,7 +859,7 @@
if (!tInfo->currContext.get()) {
return false;
}
- touch();
+
if (tInfo->currContext->clientVersion() > GLESApi_CM) {
s_gles2.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER_OES,
m_eglImage);
@@ -913,40 +870,38 @@
return true;
}
-GLuint ColorBuffer::getViewportScaledTexture() {
- return m_resizer->update(m_tex);
-}
+GLuint ColorBufferGl::getViewportScaledTexture() { return m_resizer->update(m_tex); }
-void ColorBuffer::setSync(bool debug) {
+void ColorBufferGl::setSync(bool debug) {
m_sync = (GLsync)s_egl.eglSetImageFenceANDROID(m_display, m_eglImage);
if (debug) fprintf(stderr, "%s: %u to %p\n", __func__, getHndl(), m_sync);
}
-void ColorBuffer::waitSync(bool debug) {
+void ColorBufferGl::waitSync(bool debug) {
if (debug) fprintf(stderr, "%s: %u sync %p\n", __func__, getHndl(), m_sync);
if (m_sync) {
s_egl.eglWaitImageFenceANDROID(m_display, m_sync);
}
}
-bool ColorBuffer::post(GLuint tex, float rotation, float dx, float dy) {
+bool ColorBufferGl::post(GLuint tex, float rotation, float dx, float dy) {
// NOTE: Do not call m_helper->setupContext() here!
waitSync();
return m_textureDraw->draw(tex, rotation, dx, dy);
}
-bool ColorBuffer::postWithOverlay(float rotation, float dx, float dy) {
+bool ColorBufferGl::postViewportScaledWithOverlay(float rotation, float dx, float dy) {
// NOTE: Do not call m_helper->setupContext() here!
waitSync();
return m_textureDraw->drawWithOverlay(getViewportScaledTexture(), rotation, dx, dy);
}
-void ColorBuffer::readback(unsigned char* img, bool readbackBgra) {
+void ColorBufferGl::readback(unsigned char* img, bool readbackBgra) {
RecursiveScopedContextBind context(m_helper);
if (!context.isOk()) {
return;
}
- touch();
+
waitSync();
if (bindFbo(&m_fbo, m_tex, m_needFboReattach)) {
@@ -960,12 +915,12 @@
}
}
-void ColorBuffer::readbackAsync(GLuint buffer, bool readbackBgra) {
+void ColorBufferGl::readbackAsync(GLuint buffer, bool readbackBgra) {
RecursiveScopedContextBind context(m_helper);
if (!context.isOk()) {
return;
}
- touch();
+
waitSync();
if (bindFbo(&m_fbo, m_tex, m_needFboReattach)) {
@@ -979,11 +934,9 @@
}
}
-HandleType ColorBuffer::getHndl() const {
- return mHndl;
-}
+HandleType ColorBufferGl::getHndl() const { return mHndl; }
-void ColorBuffer::onSave(android::base::Stream* stream) {
+void ColorBufferGl::onSave(android::base::Stream* stream) {
stream->putBe32(getHndl());
stream->putBe32(static_cast<uint32_t>(m_width));
stream->putBe32(static_cast<uint32_t>(m_height));
@@ -996,11 +949,10 @@
stream->putBe32(m_needFormatCheck);
}
-ColorBuffer* ColorBuffer::onLoad(android::base::Stream* stream,
- EGLDisplay p_display,
- ContextHelper* helper,
- TextureDraw* textureDraw,
- bool fastBlitSupported) {
+std::unique_ptr<ColorBufferGl> ColorBufferGl::onLoad(android::base::Stream* stream,
+ EGLDisplay p_display, ContextHelper* helper,
+ TextureDraw* textureDraw,
+ bool fastBlitSupported) {
HandleType hndl = static_cast<HandleType>(stream->getBe32());
GLuint width = static_cast<GLuint>(stream->getBe32());
GLuint height = static_cast<GLuint>(stream->getBe32());
@@ -1015,13 +967,11 @@
return create(p_display, width, height, internalFormat, frameworkFormat,
hndl, helper, textureDraw, fastBlitSupported);
}
- ColorBuffer* cb = new ColorBuffer(p_display, hndl, helper, textureDraw);
- cb->mNeedRestore = true;
+ std::unique_ptr<ColorBufferGl> cb(
+ new ColorBufferGl(p_display, hndl, width, height, helper, textureDraw));
cb->m_eglImage = eglImage;
cb->m_blitEGLImage = blitEGLImage;
assert(eglImage && blitEGLImage);
- cb->m_width = width;
- cb->m_height = height;
cb->m_internalFormat = internalFormat;
cb->m_frameworkFormat = frameworkFormat;
cb->m_fastBlitSupported = fastBlitSupported;
@@ -1029,7 +979,7 @@
return cb;
}
-void ColorBuffer::restore() {
+void ColorBufferGl::restore() {
RecursiveScopedContextBind context(m_helper);
s_gles2.glGenTextures(1, &m_tex);
s_gles2.glBindTexture(GL_TEXTURE_2D, m_tex);
@@ -1050,24 +1000,16 @@
}
}
+GLuint ColorBufferGl::getTexture() { return m_tex; }
-GLuint ColorBuffer::getTexture() {
- touch();
- return m_tex;
-}
-
-void ColorBuffer::postLayer(const ComposeLayer& l, int frameWidth, int frameHeight) {
- if (m_inUse) fprintf(stderr, "%s: cb in use\n", __func__);
+void ColorBufferGl::postLayer(const ComposeLayer& l, int frameWidth, int frameHeight) {
waitSync();
m_textureDraw->drawLayer(l, frameWidth, frameHeight, m_width, m_height,
getViewportScaledTexture());
}
-bool ColorBuffer::importMemory(ManagedDescriptor externalDescriptor, uint64_t size, bool dedicated,
- bool linearTiling, bool vulkanOnly) {
- if (m_vulkanOnly) {
- return true;
- }
+bool ColorBufferGl::importMemory(ManagedDescriptor externalDescriptor, uint64_t size,
+ bool dedicated, bool linearTiling) {
RecursiveScopedContextBind context(m_helper);
s_gles2.glCreateMemoryObjectsEXT(1, &m_memoryObject);
if (dedicated) {
@@ -1112,12 +1054,10 @@
std::vector<uint8_t> prevContents;
- if (!vulkanOnly) {
- size_t bytes;
- readContents(&bytes, nullptr);
- prevContents.resize(bytes, 0);
- readContents(&bytes, prevContents.data());
- }
+ size_t bytes;
+ readContents(&bytes, nullptr);
+ prevContents.resize(bytes, 0);
+ readContents(&bytes, prevContents.data());
s_gles2.glDeleteTextures(1, &m_tex);
s_gles2.glGenTextures(1, &m_tex);
@@ -1151,15 +1091,12 @@
m_display, s_egl.eglGetCurrentContext(), EGL_GL_TEXTURE_2D_KHR,
(EGLClientBuffer)SafePointerFromUInt(m_tex), NULL);
- if (!vulkanOnly) {
- replaceContents(prevContents.data(), m_numBytes);
- }
+ replaceContents(prevContents.data(), m_numBytes);
return true;
}
-bool ColorBuffer::importEglNativePixmap(void* pixmap, bool preserveContent) {
-
+bool ColorBufferGl::importEglNativePixmap(void* pixmap, bool preserveContent) {
EGLImageKHR image = s_egl.eglCreateImageKHR(m_display, EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR, pixmap, nullptr);
if (image == EGL_NO_IMAGE_KHR) {
@@ -1167,7 +1104,7 @@
return false;
}
- // Assume pixmap is compatible with ColorBuffer's current dimensions and internal format.
+ // Assume pixmap is compatible with ColorBufferGl's current dimensions and internal format.
EGLBoolean setInfoRes = s_egl.eglSetImageInfoANDROID(m_display, image, m_width, m_height, m_internalFormat);
if (EGL_TRUE != setInfoRes) {
@@ -1180,12 +1117,13 @@
return true;
}
-bool ColorBuffer::importEglImage(void* nativeEglImage, bool preserveContent) {
+bool ColorBufferGl::importEglImage(void* nativeEglImage, bool preserveContent) {
EGLImageKHR image = s_egl.eglImportImageANDROID(m_display, (EGLImage)nativeEglImage);
if (image == EGL_NO_IMAGE_KHR) return false;
- // Assume nativeEglImage is compatible with ColorBuffer's current dimensions and internal format.
+ // Assume nativeEglImage is compatible with ColorBufferGl's current dimensions and internal
+ // format.
EGLBoolean setInfoRes = s_egl.eglSetImageInfoANDROID(m_display, image, m_width, m_height, m_internalFormat);
if (EGL_TRUE != setInfoRes) {
@@ -1197,7 +1135,7 @@
return true;
}
-std::vector<uint8_t> ColorBuffer::getContents() {
+std::vector<uint8_t> ColorBufferGl::getContents() {
// Assume there is a current context.
size_t bytes;
readContents(&bytes, nullptr);
@@ -1206,20 +1144,20 @@
return contents;
}
-void ColorBuffer::clearStorage() {
+void ColorBufferGl::clearStorage() {
s_gles2.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)NULL);
s_egl.eglDestroyImageKHR(m_display, m_eglImage);
m_eglImage = (EGLImageKHR)0;
}
-void ColorBuffer::restoreEglImage(EGLImageKHR image) {
+void ColorBufferGl::restoreEglImage(EGLImageKHR image) {
s_gles2.glBindTexture(GL_TEXTURE_2D, m_tex);
m_eglImage = image;
s_gles2.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)m_eglImage);
}
-void ColorBuffer::rebindEglImage(EGLImageKHR image, bool preserveContent) {
+void ColorBufferGl::rebindEglImage(EGLImageKHR image, bool preserveContent) {
RecursiveScopedContextBind context(m_helper);
std::vector<uint8_t> contents;
@@ -1234,11 +1172,7 @@
}
}
-void ColorBuffer::setInUse(bool inUse) {
- m_inUse = inUse;
-}
-
-std::unique_ptr<BorrowedImageInfo> ColorBuffer::getBorrowedImageInfo() {
+std::unique_ptr<BorrowedImageInfo> ColorBufferGl::getBorrowedImageInfo() {
auto info = std::make_unique<BorrowedImageInfoGl>();
info->id = mHndl;
info->width = m_width;
@@ -1247,3 +1181,5 @@
info->onCommandsIssued = [this]() { setSync(); };
return info;
}
+
+} // namespace gfxstream
diff --git a/stream-servers/gl/ColorBufferGl.h b/stream-servers/gl/ColorBufferGl.h
index c9f62ce..5b8bd86 100644
--- a/stream-servers/gl/ColorBufferGl.h
+++ b/stream-servers/gl/ColorBufferGl.h
@@ -33,7 +33,6 @@
#include "aemu/base/ManagedDescriptor.hpp"
#include "aemu/base/files/Stream.h"
#include "render-utils/Renderer.h"
-#include "snapshot/LazySnapshotObj.h"
// From ANGLE "src/common/angleutils.h"
#define GL_BGR10_A2_ANGLEX 0x6AF9
@@ -46,60 +45,54 @@
// related things:
//
// - Every gralloc native buffer with HW read or write requirements will
-// allocate a host ColorBuffer instance. When gralloc_lock() is called,
-// the guest will use ColorBuffer::readPixels() to read the current content
+// allocate a host ColorBufferGl instance. When gralloc_lock() is called,
+// the guest will use ColorBufferGl::readPixels() to read the current content
// of the buffer. When gralloc_unlock() is later called, it will call
-// ColorBuffer::subUpdate() to send the updated pixels.
+// ColorBufferGl::subUpdate() to send the updated pixels.
//
// - Every guest window EGLSurface is implemented by a host PBuffer
-// (see WindowSurface.h) that can have a ColorBuffer instance attached to
+// (see WindowSurface.h) that can have a ColorBufferGl instance attached to
// it (through WindowSurface::attachColorBuffer()). When such an attachment
// exists, WindowSurface::flushColorBuffer() will copy the PBuffer's
-// pixel data into the ColorBuffer. The latter can then be displayed
-// in the client's UI sub-window with ColorBuffer::post().
+// pixel data into the ColorBufferGl. The latter can then be displayed
+// in the client's UI sub-window with ColorBufferGl::post().
//
// - Guest EGLImages are implemented as native gralloc buffers too.
// The guest glEGLImageTargetTexture2DOES() implementations will end up
-// calling ColorBuffer::bindToTexture() to bind the current context's
+// calling ColorBufferGl::bindToTexture() to bind the current context's
// GL_TEXTURE_2D to the buffer. Similarly, the guest versions of
// glEGLImageTargetRenderbufferStorageOES() will end up calling
-// ColorBuffer::bindToRenderbuffer().
+// ColorBufferGl::bindToRenderbuffer().
//
// This forces the implementation to use a host EGLImage to implement each
-// ColorBuffer.
+// ColorBufferGl.
//
// As an additional twist.
-class ColorBuffer :
- public android::snapshot::LazySnapshotObj<ColorBuffer> {
+namespace gfxstream {
+
+class ColorBufferGl {
public:
- // Create a new ColorBuffer instance.
- // |p_display| is the host EGLDisplay handle.
- // |p_width| and |p_height| are the buffer's dimensions in pixels.
- // |p_internalFormat| is the internal OpenGL pixel format to use, valid
+ // Create a new ColorBufferGl instance.
+ // |display| is the host EGLDisplay handle.
+ // |width| and |height| are the buffer's dimensions in pixels.
+ // |internalFormat| is the internal OpenGL pixel format to use, valid
// values
// are: GL_RGB, GL_RGB565, GL_RGBA, GL_RGB5_A1_OES and GL_RGBA4_OES.
// Implementation is free to use something else though.
- // |p_frameworkFormat| specifies the original format of the guest
- // color buffer so that we know how to convert to |p_internalFormat|,
- // if necessary (otherwise, p_frameworkFormat ==
+ // |frameworkFormat| specifies the original format of the guest
+ // color buffer so that we know how to convert to |internalFormat|,
+ // if necessary (otherwise, frameworkFormat ==
// FRAMEWORK_FORMAT_GL_COMPATIBLE).
// It is assumed underlying EGL has EGL_KHR_gl_texture_2D_image.
// Returns NULL on failure.
- // |fastBlitSupported|: whether or not this ColorBuffer can be
+ // |fastBlitSupported|: whether or not this ColorBufferGl can be
// blitted and posted to swapchain without context switches.
- // |vulkanOnly|: whether or not the guest interacts entirely with Vulkan
- // and does not use the GL based API.
- static ColorBuffer* create(EGLDisplay p_display,
- int p_width,
- int p_height,
- GLint p_internalFormat,
- FrameworkFormat p_frameworkFormat,
- HandleType hndl,
- ContextHelper* helper,
- TextureDraw* textureDraw,
- bool fastBlitSupported,
- bool vulkanOnly = false);
+ static std::unique_ptr<ColorBufferGl> create(EGLDisplay display, int width, int height,
+ GLint internalFormat,
+ FrameworkFormat frameworkFormat, HandleType handle,
+ ContextHelper* helper, TextureDraw* textureDraw,
+ bool fastBlitSupported);
// Sometimes things happen and we need to reformat the GL texture
// used. This function replaces the format of the underlying texture
@@ -107,14 +100,14 @@
void reformat(GLint internalformat, GLenum type);
// Destructor.
- ~ColorBuffer();
+ ~ColorBufferGl();
- // Return ColorBuffer width and height in pixels
+ // Return ColorBufferGl width and height in pixels
GLuint getWidth() const { return m_width; }
GLuint getHeight() const { return m_height; }
GLint getInternalFormat() const { return m_internalFormat; }
- // Read the ColorBuffer instance's pixel values into host memory.
+ // Read the ColorBufferGl instance's pixel values into host memory.
void readPixels(int x,
int y,
int width,
@@ -126,7 +119,7 @@
// to the size of width x height, then clipping a |rect| from the
// screen defined by width x height.
void readPixelsScaled(int width, int height, GLenum p_format, GLenum p_type, int skinRotation,
- void* pixels, emugl::Rect rect);
+ emugl::Rect rect, void* pixels);
// Read cached YUV pixel values into host memory.
void readPixelsYUVCached(int x,
@@ -136,23 +129,18 @@
void* pixels,
uint32_t pixels_size);
- void swapYUVTextures(uint32_t texture_type, uint32_t* textures);
+ void swapYUVTextures(FrameworkFormat texture_type, GLuint* textures);
- // Update the ColorBuffer instance's pixel values from host memory.
+ // Update the ColorBufferGl instance's pixel values from host memory.
// |p_format / p_type| are the desired OpenGL color buffer format
// and data type.
// Otherwise, subUpdate() will explicitly convert |pixels|
// to be in |p_format|.
- void subUpdate(int x,
- int y,
- int width,
- int height,
- GLenum p_format,
- GLenum p_type,
- void* pixels);
+ void subUpdate(int x, int y, int width, int height, GLenum p_format, GLenum p_type,
+ const void* pixels);
void subUpdateFromFrameworkFormat(int x, int y, int width, int height,
FrameworkFormat fwkFormat, GLenum p_format, GLenum p_type,
- void* pixels);
+ const void* pixels);
// Completely replaces contents, assuming that |pixels| is a buffer
// that is allocated and filled with the same format.
@@ -162,7 +150,7 @@
// If the framework format is YUV, it will read back as raw YUV data.
bool readContents(size_t* numBytes, void* pixels);
- // Draw a ColorBuffer instance, i.e. blit it to the current guest
+ // Draw a ColorBufferGl instance, i.e. blit it to the current guest
// framebuffer object / window surface. This doesn't display anything.
bool draw();
@@ -174,40 +162,38 @@
// |rotation| is the rotation angle in degrees, clockwise in the GL
// coordinate space.
bool post(GLuint tex, float rotation, float dx, float dy);
- // Post this ColorBuffer to the host native sub-window and apply
+ // Post this ColorBufferGl to the host native sub-window and apply
// the device screen overlay (if there is one).
// |rotation| is the rotation angle in degrees, clockwise in the GL
// coordinate space.
- bool postWithOverlay(float rotation, float dx, float dy);
+ bool postViewportScaledWithOverlay(float rotation, float dx, float dy);
- // Bind the current context's EGL_TEXTURE_2D texture to this ColorBuffer's
+ // Bind the current context's EGL_TEXTURE_2D texture to this ColorBufferGl's
// EGLImage. This is intended to implement glEGLImageTargetTexture2DOES()
// for all GLES versions.
bool bindToTexture();
bool bindToTexture2();
// Bind the current context's EGL_RENDERBUFFER_OES render buffer to this
- // ColorBuffer's EGLImage. This is intended to implement
+ // ColorBufferGl's EGLImage. This is intended to implement
// glEGLImageTargetRenderbufferStorageOES() for all GLES versions.
bool bindToRenderbuffer();
// Copy the content of the current context's read surface to this
- // ColorBuffer. This is used from WindowSurface::flushColorBuffer().
+ // ColorBufferGl. This is used from WindowSurface::flushColorBuffer().
// Return true on success, false on failure (e.g. no current context).
bool blitFromCurrentReadBuffer();
- // Read the content of the whole ColorBuffer as 32-bit RGBA pixels.
+ // Read the content of the whole ColorBufferGl as 32-bit RGBA pixels.
// |img| must be a buffer large enough (i.e. width * height * 4).
void readback(unsigned char* img, bool readbackBgra = false);
// readback() but async (to the specified |buffer|)
void readbackAsync(GLuint buffer, bool readbackBgra = false);
void onSave(android::base::Stream* stream);
- static ColorBuffer* onLoad(android::base::Stream* stream,
- EGLDisplay p_display,
- ContextHelper* helper,
- TextureDraw* textureDraw,
- bool fastBlitSupported);
+ static std::unique_ptr<ColorBufferGl> onLoad(android::base::Stream* stream,
+ EGLDisplay p_display, ContextHelper* helper,
+ TextureDraw* textureDraw, bool fastBlitSupported);
HandleType getHndl() const;
@@ -217,21 +203,18 @@
std::unique_ptr<BorrowedImageInfo> getBorrowedImageInfo();
- // ColorBuffer backing change methods
+ // ColorBufferGl backing change methods
//
// Change to opaque fd or opaque win32 handle-backed VkDeviceMemory
// via GL_EXT_memory_objects
bool importMemory(android::base::ManagedDescriptor externalDescriptor, uint64_t size,
- bool dedicated, bool linearTiling, bool vulkanOnly);
+ bool dedicated, bool linearTiling);
// Change to EGL native pixmap
bool importEglNativePixmap(void* pixmap, bool preserveContent);
// Change to some other native EGL image. nativeEglImage must not have
// been created from our s_egl.eglCreateImage.
bool importEglImage(void* nativeEglImage, bool preserveContent);
- void setInUse(bool inUse);
- bool isInUse() const { return m_inUse; }
-
void setSync(bool debug = false);
void waitSync(bool debug = false);
void setDisplay(uint32_t displayId) { m_displayId = displayId; }
@@ -242,24 +225,24 @@
void restore();
private:
- ColorBuffer(EGLDisplay display, HandleType hndl, ContextHelper* helper,
- TextureDraw* textureDraw);
- // Helper function to get contents.
- std::vector<uint8_t> getContents();
- // Helper function to clear current EGL image.
- void clearStorage();
- // Helper function to bind EGL image as texture. Assumes storage cleared.
- void restoreEglImage(EGLImageKHR image);
- // Helper function that does the above two operations in one go.
- void rebindEglImage(EGLImageKHR image, bool preserveContent);
+ ColorBufferGl(EGLDisplay display, HandleType hndl, GLuint width, GLuint height,
+ ContextHelper* helper, TextureDraw* textureDraw);
+ // Helper function to get contents.
+ std::vector<uint8_t> getContents();
+ // Helper function to clear current EGL image.
+ void clearStorage();
+ // Helper function to bind EGL image as texture. Assumes storage cleared.
+ void restoreEglImage(EGLImageKHR image);
+ // Helper function that does the above two operations in one go.
+ void rebindEglImage(EGLImageKHR image, bool preserveContent);
private:
GLuint m_tex = 0;
GLuint m_blitTex = 0;
EGLImageKHR m_eglImage = nullptr;
EGLImageKHR m_blitEGLImage = nullptr;
- GLuint m_width = 0;
- GLuint m_height = 0;
+ const GLuint m_width = 0;
+ const GLuint m_height = 0;
GLuint m_fbo = 0;
GLint m_internalFormat = 0;
GLint m_sizedInternalFormat = 0;
@@ -306,21 +289,6 @@
bool m_BRSwizzle = false;
};
-typedef std::shared_ptr<ColorBuffer> ColorBufferPtr;
+typedef std::shared_ptr<ColorBufferGl> ColorBufferGlPtr;
-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;
-};
-
-typedef std::unordered_map<HandleType, ColorBufferRef> ColorBufferMap;
-typedef std::unordered_multiset<HandleType> ColorBufferSet;
+} // namespace gfxstream
diff --git a/stream-servers/gl/DisplayGl.cpp b/stream-servers/gl/DisplayGl.cpp
index 86c9f49..915394f 100644
--- a/stream-servers/gl/DisplayGl.cpp
+++ b/stream-servers/gl/DisplayGl.cpp
@@ -53,16 +53,14 @@
mTextureDraw->prepareForDrawLayer();
hasDrawLayer = true;
}
- layer.colorBuffer->postLayer(*layer.layerOptions,
- post.frameWidth,
- post.frameHeight);
+ layer.colorBuffer->glOpPostLayer(*layer.layerOptions, post.frameWidth,
+ post.frameHeight);
} else if (layer.overlayOptions) {
if (hasDrawLayer) {
ERR("Cannot mix colorBuffer.postLayer with postWithOverlay!");
}
- layer.colorBuffer->postWithOverlay(layer.overlayOptions->rotation,
- layer.overlayOptions->dx,
- layer.overlayOptions->dy);
+ layer.colorBuffer->glOpPostViewportScaledWithOverlay(
+ layer.overlayOptions->rotation, layer.overlayOptions->dx, layer.overlayOptions->dy);
}
}
if (hasDrawLayer) {
diff --git a/stream-servers/gl/DisplayGl.h b/stream-servers/gl/DisplayGl.h
index c421481..a82f520 100644
--- a/stream-servers/gl/DisplayGl.h
+++ b/stream-servers/gl/DisplayGl.h
@@ -14,17 +14,17 @@
#pragma once
-#include <atomic>
-#include <future>
-
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
+#include <atomic>
+#include <future>
+
+#include "ColorBuffer.h"
#include "Display.h"
#include "Hwc2.h"
-#include "gl/ColorBufferGl.h"
class DisplayGl : public gfxstream::Display {
public:
diff --git a/stream-servers/gl/EmulatedEglWindowSurface.cpp b/stream-servers/gl/EmulatedEglWindowSurface.cpp
index 9899aaa..426b3a4 100644
--- a/stream-servers/gl/EmulatedEglWindowSurface.cpp
+++ b/stream-servers/gl/EmulatedEglWindowSurface.cpp
@@ -122,7 +122,7 @@
}
}
- mAttachedColorBuffer->blitFromCurrentReadBuffer();
+ mAttachedColorBuffer->glOpBlitFromCurrentReadBuffer();
if (needToSet) {
// restore current context/surface
diff --git a/stream-servers/gl/EmulatedEglWindowSurface.h b/stream-servers/gl/EmulatedEglWindowSurface.h
index 779a4c1..a3a0108 100644
--- a/stream-servers/gl/EmulatedEglWindowSurface.h
+++ b/stream-servers/gl/EmulatedEglWindowSurface.h
@@ -16,13 +16,14 @@
#pragma once
-#include <memory>
-#include <unordered_set>
-#include <unordered_map>
-
#include <EGL/egl.h>
#include <GLES/gl.h>
+#include <memory>
+#include <unordered_map>
+#include <unordered_set>
+
+#include "ColorBuffer.h"
#include "Handle.h"
#include "gl/ColorBufferGl.h"
#include "gl/EmulatedEglContext.h"
diff --git a/stream-servers/gl/EmulationGl.cpp b/stream-servers/gl/EmulationGl.cpp
index 86fcbe4..aa72329 100644
--- a/stream-servers/gl/EmulationGl.cpp
+++ b/stream-servers/gl/EmulationGl.cpp
@@ -594,6 +594,29 @@
}
}
+ContextHelper* EmulationGl::getColorBufferContextHelper() {
+ if (!mPbufferSurface) {
+ return nullptr;
+ }
+
+ const auto* surfaceGl = static_cast<const DisplaySurfaceGl*>(mPbufferSurface->getImpl());
+ return surfaceGl->getContextHelper();
+}
+
+std::unique_ptr<ColorBufferGl> EmulationGl::createColorBuffer(uint32_t width, uint32_t height,
+ GLenum internalFormat,
+ FrameworkFormat frameworkFormat,
+ HandleType handle) {
+ return ColorBufferGl::create(mEglDisplay, width, height, internalFormat, frameworkFormat,
+ handle, getColorBufferContextHelper(), mTextureDraw.get(),
+ isFastBlitSupported());
+}
+
+std::unique_ptr<ColorBufferGl> EmulationGl::loadColorBuffer(android::base::Stream* stream) {
+ return ColorBufferGl::onLoad(stream, mEglDisplay, getColorBufferContextHelper(),
+ mTextureDraw.get(), isFastBlitSupported());
+}
+
std::unique_ptr<EmulatedEglContext> EmulationGl::createEmulatedEglContext(
uint32_t emulatedEglConfigIndex,
const EmulatedEglContext* sharedContext,
diff --git a/stream-servers/gl/EmulationGl.h b/stream-servers/gl/EmulationGl.h
index 65168ca..6146561 100644
--- a/stream-servers/gl/EmulationGl.h
+++ b/stream-servers/gl/EmulationGl.h
@@ -14,24 +14,24 @@
#pragma once
-#include <array>
-#include <memory>
-#include <string>
-#include <optional>
-#include <unordered_set>
-
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES/gl.h>
#include <GLES3/gl3.h>
-#include "ContextHelper.h"
+#include <array>
+#include <memory>
+#include <optional>
+#include <string>
+#include <unordered_set>
+
+#include "ColorBufferGl.h"
#include "Compositor.h"
#include "CompositorGl.h"
+#include "ContextHelper.h"
#include "Display.h"
#include "DisplayGl.h"
#include "DisplaySurface.h"
-#include "EmulatedEglContext.h"
#include "EmulatedEglConfig.h"
#include "EmulatedEglContext.h"
#include "EmulatedEglFenceSync.h"
@@ -40,6 +40,7 @@
#include "OpenGLESDispatch/GLESv2Dispatch.h"
#include "ReadbackWorkerGl.h"
#include "TextureDraw.h"
+#include "aemu/base/files/Stream.h"
#define EGL_NO_CONFIG ((EGLConfig)0)
@@ -85,14 +86,18 @@
ReadbackWorkerGl* getReadbackWorker() { return mReadbackWorkerGl.get(); }
- // TODO(b/233939967): Remove after adding ColorBufferGl and EmulationGl::createColorBuffer().
- TextureDraw* getTextureDraw() const { return mTextureDraw.get(); }
-
using GlesUuid = std::array<uint8_t, GL_UUID_SIZE_EXT>;
const std::optional<GlesUuid> getGlesDeviceUuid() const { return mGlesDeviceUuid; }
void setUseBoundSurfaceContextForDisplay(bool use);
+ std::unique_ptr<ColorBufferGl> createColorBuffer(uint32_t width, uint32_t height,
+ GLenum internalFormat,
+ FrameworkFormat frameworkFormat,
+ HandleType handle);
+
+ std::unique_ptr<ColorBufferGl> loadColorBuffer(android::base::Stream* stream);
+
std::unique_ptr<EmulatedEglContext> createEmulatedEglContext(
uint32_t emulatedEglConfigIndex,
const EmulatedEglContext* shareContext,
@@ -128,6 +133,8 @@
EmulationGl() = default;
+ ContextHelper* getColorBufferContextHelper();
+
EGLDisplay mEglDisplay = EGL_NO_DISPLAY;
EGLint mEglVersionMajor = 0;
EGLint mEglVersionMinor = 0;
diff --git a/stream-servers/gl/ReadbackWorkerGl.cpp b/stream-servers/gl/ReadbackWorkerGl.cpp
index 41a0c93..426f86b 100644
--- a/stream-servers/gl/ReadbackWorkerGl.cpp
+++ b/stream-servers/gl/ReadbackWorkerGl.cpp
@@ -17,6 +17,7 @@
#include <string.h>
+#include "ColorBuffer.h"
#include "ContextHelper.h"
#include "OpenGLESDispatch/DispatchTables.h"
#include "OpenGLESDispatch/EGLDispatch.h"
@@ -165,7 +166,7 @@
r.m_readbackCount++;
r.mPrevReadPixelsIndex = readAt;
- cb->readbackAsync(r.mBuffers[readAt], readbackBgra);
+ cb->glOpReadbackAsync(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
diff --git a/stream-servers/gl/YUVConverter.cpp b/stream-servers/gl/YUVConverter.cpp
index f9735a0..d06f768 100644
--- a/stream-servers/gl/YUVConverter.cpp
+++ b/stream-servers/gl/YUVConverter.cpp
@@ -461,7 +461,8 @@
s_gles2.glActiveTexture(GL_TEXTURE0);
}
-static void readYUVTex(GLuint tex, FrameworkFormat format, YUVPlane plane, void* pixels) {
+static void readYUVTex(GLuint tex, FrameworkFormat format, YUVPlane plane, void* pixels,
+ uint32_t pixelsStride) {
YUV_DEBUG_LOG("format%d plane:%d pixels:%p", format, plane, pixels);
GLuint prevTexture = 0;
@@ -470,6 +471,10 @@
GLint prevAlignment = 0;
s_gles2.glGetIntegerv(GL_PACK_ALIGNMENT, &prevAlignment);
s_gles2.glPixelStorei(GL_PACK_ALIGNMENT, 1);
+ GLint prevStride = 0;
+ s_gles2.glGetIntegerv(GL_PACK_ROW_LENGTH, &prevStride);
+ s_gles2.glPixelStorei(GL_PACK_ROW_LENGTH, pixelsStride);
+
const GLenum pixelFormat = getGlPixelFormat(format, plane);
const GLenum pixelType = getGlPixelType(format, plane);
if (s_gles2.glGetTexImage) {
@@ -478,6 +483,7 @@
YUV_DEBUG_LOG("empty glGetTexImage");
}
+ s_gles2.glPixelStorei(GL_PACK_ROW_LENGTH, prevStride);
s_gles2.glPixelStorei(GL_PACK_ALIGNMENT, prevAlignment);
s_gles2.glBindTexture(GL_TEXTURE_2D, prevTexture);
}
@@ -852,10 +858,11 @@
&vWidth, &vHeight, &vOffsetBytes, &vStridePixels, &vStrideBytes);
if (isInterleaved(mFormat)) {
- readYUVTex(mTextureV, mFormat, YUVPlane::UV, pixels + std::min(uOffsetBytes, vOffsetBytes));
+ readYUVTex(mTextureV, mFormat, YUVPlane::UV, pixels + std::min(uOffsetBytes, vOffsetBytes),
+ uStridePixels);
} else {
- readYUVTex(mTextureU, mFormat, YUVPlane::U, pixels + uOffsetBytes);
- readYUVTex(mTextureV, mFormat, YUVPlane::V, pixels + vOffsetBytes);
+ readYUVTex(mTextureU, mFormat, YUVPlane::U, pixels + uOffsetBytes, uStridePixels);
+ readYUVTex(mTextureV, mFormat, YUVPlane::V, pixels + vOffsetBytes, vStridePixels);
}
if (mFormat == FRAMEWORK_FORMAT_NV12 && mColorBufferFormat == FRAMEWORK_FORMAT_YUV_420_888) {
@@ -863,12 +870,10 @@
}
// Read the Y plane last because so that we can use it as a scratch space.
- readYUVTex(mTextureY, mFormat, YUVPlane::Y, pixels + yOffsetBytes);
+ readYUVTex(mTextureY, mFormat, YUVPlane::Y, pixels + yOffsetBytes, yStridePixels);
}
-void YUVConverter::swapTextures(uint32_t type, uint32_t* textures) {
- FrameworkFormat format = static_cast<FrameworkFormat>(type);
-
+void YUVConverter::swapTextures(FrameworkFormat format, GLuint* textures) {
if (isInterleaved(format)) {
std::swap(textures[0], mTextureY);
std::swap(textures[1], mTextureU);
diff --git a/stream-servers/gl/YUVConverter.h b/stream-servers/gl/YUVConverter.h
index 8cddee1..23dde61 100644
--- a/stream-servers/gl/YUVConverter.h
+++ b/stream-servers/gl/YUVConverter.h
@@ -71,7 +71,7 @@
// if size mismatches, will read nothing.
void readPixels(uint8_t* pixels, uint32_t pixels_size);
- void swapTextures(uint32_t type, uint32_t* textures);
+ void swapTextures(FrameworkFormat type, GLuint* textures);
// public so other classes can call
static void createYUVGLTex(GLenum textureUnit,
diff --git a/stream-servers/tests/FrameBuffer_unittest.cpp b/stream-servers/tests/FrameBuffer_unittest.cpp
index 63915af..410986d 100644
--- a/stream-servers/tests/FrameBuffer_unittest.cpp
+++ b/stream-servers/tests/FrameBuffer_unittest.cpp
@@ -540,14 +540,14 @@
EXPECT_TRUE(mFb->isFastBlitSupported());
mFb->lock();
- EXPECT_EQ(mFb->isFastBlitSupported(), mFb->findColorBuffer(handle)->isFastBlitSupported());
+ EXPECT_EQ(mFb->isFastBlitSupported(), mFb->findColorBuffer(handle)->glOpIsFastBlitSupported());
mFb->unlock();
saveSnapshot();
loadSnapshot();
mFb->lock();
- EXPECT_EQ(mFb->isFastBlitSupported(), mFb->findColorBuffer(handle)->isFastBlitSupported());
+ EXPECT_EQ(mFb->isFastBlitSupported(), mFb->findColorBuffer(handle)->glOpIsFastBlitSupported());
mFb->unlock();
mFb->closeColorBuffer(handle);
diff --git a/stream-servers/vulkan/VkAndroidNativeBuffer.cpp b/stream-servers/vulkan/VkAndroidNativeBuffer.cpp
index 096cc8c..07a1666 100644
--- a/stream-servers/vulkan/VkAndroidNativeBuffer.cpp
+++ b/stream-servers/vulkan/VkAndroidNativeBuffer.cpp
@@ -511,8 +511,6 @@
// If we used the Vulkan image without copying it back
// to the CPU, reset the layout to PRESENT.
if (anbInfo->useVulkanNativeImage) {
- fb->setColorBufferInUse(anbInfo->colorBufferHandle, true);
-
VkCommandBufferBeginInfo beginInfo = {
VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
0,
@@ -761,7 +759,6 @@
if (anbInfo->useVulkanNativeImage) {
VK_ANB_DEBUG_OBJ(anbInfoPtr, "using native image, so use sync thread to wait");
- fb->setColorBufferInUse(anbInfo->colorBufferHandle, false);
// Queue wait to sync thread with completion callback
// Pass anbInfo by value to get a ref
SyncThread::get()->triggerGeneral(