Ensure glProgramBinary initializes uniform and attrib info
Adds Scoped* helper classes to hopefully make writing tests easier.
Bug: b/330392312
Test: GfxstreamEnd2EndTests
Change-Id: Ibb2c957682dd7173bd6f839bc1c379d47c4e0318
diff --git a/common/end2end/GfxstreamEnd2EndGlTests.cpp b/common/end2end/GfxstreamEnd2EndGlTests.cpp
index 6b6934f..ac3934d 100644
--- a/common/end2end/GfxstreamEnd2EndGlTests.cpp
+++ b/common/end2end/GfxstreamEnd2EndGlTests.cpp
@@ -12,7 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include <log/log.h>
+
#include "GfxstreamEnd2EndTests.h"
+#include "drm_fourcc.h"
namespace gfxstream {
namespace tests {
@@ -26,39 +29,106 @@
using testing::Le;
using testing::Not;
-class GfxstreamEnd2EndGlTest : public GfxstreamEnd2EndTest {};
+struct PixelR8G8B8A8 {
+ PixelR8G8B8A8(uint8_t rr, uint8_t gg, uint8_t bb, uint8_t aa) : r(rr), g(gg), b(bb), a(aa) {}
+
+ PixelR8G8B8A8(int xx, int yy, uint8_t rr, uint8_t gg, uint8_t bb, uint8_t aa)
+ : x(xx), y(yy), r(rr), g(gg), b(bb), a(aa) {}
+
+ std::optional<int> x;
+ std::optional<int> y;
+
+ uint8_t r;
+ uint8_t g;
+ uint8_t b;
+ uint8_t a;
+
+ std::string ToString() const {
+ std::string ret = std::string("Pixel");
+ if (x) {
+ ret += std::string(" x:") + std::to_string(*x);
+ }
+ if (y) {
+ ret += std::string(" y:") + std::to_string(*y);
+ }
+ ret += std::string(" {");
+ ret += std::string(" r:") + std::to_string(static_cast<int>(r));
+ ret += std::string(" g:") + std::to_string(static_cast<int>(g));
+ ret += std::string(" b:") + std::to_string(static_cast<int>(b));
+ ret += std::string(" a:") + std::to_string(static_cast<int>(a));
+ ret += std::string(" }");
+ return ret;
+ }
+
+ friend void PrintTo(const PixelR8G8B8A8& pixel, std::ostream* os) { *os << pixel.ToString(); }
+};
+
+MATCHER_P4(IsOkWithRGBA, r, g, b, a,
+ std::string(" equals ") + PixelR8G8B8A8(r, g, b, a).ToString()) {
+ const auto& actual = arg;
+
+ if (actual.ok() && actual.value().r == r && actual.value().g == g && actual.value().b == b &&
+ actual.value().a == a) {
+ return true;
+ }
+
+ if (actual.ok()) {
+ *result_listener << "actual: " << actual.value().ToString();
+ } else {
+ *result_listener << "actual: {" << " error: " << actual.error() << " };";
+ }
+ return false;
+}
+
+class GfxstreamEnd2EndGlTest : public GfxstreamEnd2EndTest {
+ protected:
+ GlExpected<PixelR8G8B8A8> GetPixelAt(GLint x, GLint y) {
+ if (!mGl) {
+ return android::base::unexpected("GL not available, running with `with_gl = false`?");
+ }
+
+ GLubyte rgba[4] = {0, 0, 0, 0};
+ mGl->glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, rgba);
+
+ if (GLenum error = mGl->glGetError(); error != GL_NO_ERROR) {
+ return android::base::unexpected("Failed to glReadPixels() with error " +
+ std::to_string(error));
+ }
+
+ return PixelR8G8B8A8(x, y, rgba[0], rgba[1], rgba[2], rgba[3]);
+ }
+
+ void SetUp() override {
+ GfxstreamEnd2EndTest::SetUp();
+
+ SetUpEglContextAndSurface(2, mSurfaceWidth, mSurfaceHeight, &mDisplay, &mContext,
+ &mSurface);
+ }
+
+ void TearDown() override {
+ TearDownEglContextAndSurface(mDisplay, mContext, mSurface);
+
+ GfxstreamEnd2EndTest::TearDown();
+ }
+
+ int mSurfaceWidth = 32;
+ int mSurfaceHeight = 32;
+ EGLDisplay mDisplay;
+ EGLContext mContext;
+ EGLSurface mSurface;
+};
TEST_P(GfxstreamEnd2EndGlTest, BasicViewport) {
- constexpr const int width = 32;
- constexpr const int height = 32;
-
- EGLDisplay display;
- EGLContext context;
- EGLSurface surface;
- SetUpEglContextAndSurface(2, width, height, &display, &context, &surface);
-
GLint viewport[4] = {};
mGl->glGetIntegerv(GL_VIEWPORT, viewport);
EXPECT_THAT(viewport[0], Eq(0));
EXPECT_THAT(viewport[1], Eq(0));
- EXPECT_THAT(viewport[2], Eq(width));
- EXPECT_THAT(viewport[3], Eq(height));
-
- TearDownEglContextAndSurface(display, context, surface);
+ EXPECT_THAT(viewport[2], Eq(mSurfaceWidth));
+ EXPECT_THAT(viewport[3], Eq(mSurfaceHeight));
}
TEST_P(GfxstreamEnd2EndGlTest, CreateWindowSurface) {
-
- EGLDisplay display = mGl->eglGetDisplay(EGL_DEFAULT_DISPLAY);
- ASSERT_THAT(display, Not(Eq(EGL_NO_DISPLAY)));
-
- int versionMajor = 0;
- int versionMinor = 0;
- ASSERT_THAT(mGl->eglInitialize(display, &versionMajor, &versionMinor), IsTrue());
-
- ASSERT_THAT(mGl->eglBindAPI(EGL_OPENGL_ES_API), IsTrue());
-
// clang-format off
static const EGLint configAttributes[] = {
EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
@@ -68,11 +138,13 @@
// clang-format on
int numConfigs = 0;
- ASSERT_THAT(mGl->eglChooseConfig(display, configAttributes, nullptr, 1, &numConfigs), IsTrue());
+ ASSERT_THAT(mGl->eglChooseConfig(mDisplay, configAttributes, nullptr, 1, &numConfigs),
+ IsTrue());
ASSERT_THAT(numConfigs, Gt(0));
EGLConfig config = nullptr;
- ASSERT_THAT(mGl->eglChooseConfig(display, configAttributes, &config, 1, &numConfigs), IsTrue());
+ ASSERT_THAT(mGl->eglChooseConfig(mDisplay, configAttributes, &config, 1, &numConfigs),
+ IsTrue());
ASSERT_THAT(config, Not(Eq(nullptr)));
// clang-format off
@@ -82,7 +154,7 @@
};
// clang-format on
- EGLContext context = mGl->eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs);
+ EGLContext context = mGl->eglCreateContext(mDisplay, config, EGL_NO_CONTEXT, contextAttribs);
ASSERT_THAT(context, Not(Eq(EGL_NO_CONTEXT)));
constexpr const int width = 32;
@@ -90,10 +162,10 @@
auto anw = mAnwHelper->createNativeWindowForTesting(mGralloc.get(), width, height);
- EGLSurface surface = mGl->eglCreateWindowSurface(display, config, anw, nullptr);
+ EGLSurface surface = mGl->eglCreateWindowSurface(mDisplay, config, anw, nullptr);
ASSERT_THAT(surface, Not(Eq(EGL_NO_SURFACE)));
- ASSERT_THAT(mGl->eglMakeCurrent(display, surface, surface, context), IsTrue());
+ ASSERT_THAT(mGl->eglMakeCurrent(mDisplay, surface, surface, context), IsTrue());
constexpr const int iterations = 120;
for (int i = 0; i < iterations; i++) {
@@ -101,48 +173,29 @@
mGl->glClearColor(1.0f, 0.0f, static_cast<float>(i) / static_cast<float>(iterations), 1.0f);
mGl->glClear(GL_COLOR_BUFFER_BIT);
mGl->glFinish();
- mGl->eglSwapBuffers(display, surface);
+ mGl->eglSwapBuffers(mDisplay, surface);
}
- ASSERT_THAT(mGl->eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT), IsTrue());
- ASSERT_THAT(mGl->eglDestroyContext(display, context), IsTrue());
- ASSERT_THAT(mGl->eglDestroySurface(display, surface), IsTrue());
- mAnwHelper->release(anw);
+ ASSERT_THAT(mGl->eglDestroyContext(mDisplay, context), IsTrue());
+ ASSERT_THAT(mGl->eglDestroySurface(mDisplay, surface), IsTrue());
- TearDownGuest();
+ mAnwHelper->release(anw);
}
TEST_P(GfxstreamEnd2EndGlTest, SwitchContext) {
- constexpr const int width = 32;
- constexpr const int height = 32;
-
- EGLDisplay display;
- EGLContext context;
- EGLSurface surface;
- SetUpEglContextAndSurface(2, width, height, &display, &context, &surface);
-
- ASSERT_THAT(mGl->eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT), IsTrue());
+ ASSERT_THAT(mGl->eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT),
+ IsTrue());
for (int i = 0; i < 100; i++) {
- ASSERT_THAT(mGl->eglMakeCurrent(display, surface, surface, context), IsTrue());
- ASSERT_THAT(mGl->eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT), IsTrue());
+ ASSERT_THAT(mGl->eglMakeCurrent(mDisplay, mSurface, mSurface, mContext), IsTrue());
+ ASSERT_THAT(mGl->eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT),
+ IsTrue());
}
-
- TearDownEglContextAndSurface(display, context, surface);
}
TEST_P(GfxstreamEnd2EndGlTest, MappedMemory) {
- constexpr const int width = 32;
- constexpr const int height = 32;
-
- EGLDisplay display;
- EGLContext context;
- EGLSurface surface;
- SetUpEglContextAndSurface(3, width, height, &display, &context, &surface);
-
constexpr GLsizei kBufferSize = 64;
- GLuint buffer;
- mGl->glGenBuffers(1, &buffer);
+ ScopedGlBuffer buffer(*mGl);
mGl->glBindBuffer(GL_ARRAY_BUFFER, buffer);
mGl->glBufferData(GL_ARRAY_BUFFER, kBufferSize, 0, GL_DYNAMIC_DRAW);
@@ -176,9 +229,6 @@
}
mGl->glBindBuffer(GL_ARRAY_BUFFER, 0);
- mGl->glDeleteBuffers(1, &buffer);
-
- TearDownEglContextAndSurface(display, context, surface);
}
TEST_P(GfxstreamEnd2EndGlTest, ContextStrings) {
@@ -270,14 +320,6 @@
}
TEST_P(GfxstreamEnd2EndGlTest, FramebufferFetchShader) {
- constexpr const int width = 32;
- constexpr const int height = 32;
-
- EGLDisplay display;
- EGLContext context;
- EGLSurface surface;
- SetUpEglContextAndSurface(3, width, height, &display, &context, &surface);
-
const std::string extensionsString = (const char*)mGl->glGetString(GL_EXTENSIONS);
ASSERT_THAT(extensionsString, Not(IsEmpty()));
@@ -297,23 +339,12 @@
auto result = SetUpShader(GL_FRAGMENT_SHADER, shaderSource);
if (result.ok()) {
ASSERT_THAT(supportsFramebufferFetch, Eq(GL_TRUE));
- mGl->glDeleteShader(*result);
} else {
ASSERT_THAT(supportsFramebufferFetch, Eq(GL_FALSE));
}
-
- TearDownEglContextAndSurface(display, context, surface);
}
TEST_P(GfxstreamEnd2EndGlTest, ConstantMatrixShader) {
- constexpr const int width = 32;
- constexpr const int height = 32;
-
- EGLDisplay display;
- EGLContext context;
- EGLSurface surface;
- SetUpEglContextAndSurface(2, width, height, &display, &context, &surface);
-
const std::string shaderSource = R"(\
#version 300 es
precision mediump float;
@@ -334,20 +365,9 @@
auto result = SetUpShader(GL_VERTEX_SHADER, shaderSource);
ASSERT_THAT(result, IsOk());
- mGl->glDeleteShader(result.value());
-
- TearDownEglContextAndSurface(display, context, surface);
}
TEST_P(GfxstreamEnd2EndGlTest, Draw) {
- constexpr const int width = 32;
- constexpr const int height = 32;
-
- EGLDisplay display;
- EGLContext context;
- EGLSurface surface;
- SetUpEglContextAndSurface(2, width, height, &display, &context, &surface);
-
const std::string vertSource = R"(\
#version 300 es
precision highp float;
@@ -378,9 +398,7 @@
}
)";
- auto programResult = SetUpProgram(vertSource, fragSource);
- ASSERT_THAT(programResult, IsOk());
- auto program = programResult.value();
+ ScopedGlProgram program = GL_ASSERT(SetUpProgram(vertSource, fragSource));
GLint transformUniformLocation = mGl->glGetUniformLocation(program, "transform");
mGl->glEnableVertexAttribArray(0);
@@ -398,8 +416,7 @@
// clang-format on
};
- GLuint buffer;
- mGl->glGenBuffers(1, &buffer);
+ ScopedGlBuffer buffer(*mGl);
mGl->glBindBuffer(GL_ARRAY_BUFFER, buffer);
mGl->glBufferData(GL_ARRAY_BUFFER, sizeof(vertexAttrs), vertexAttrs, GL_STATIC_DRAW);
@@ -430,14 +447,303 @@
}
mGl->glFinish();
-
mGl->glBindBuffer(GL_ARRAY_BUFFER, 0);
- mGl->glDeleteBuffers(1, &buffer);
-
mGl->glUseProgram(0);
- mGl->glDeleteProgram(program);
+}
- TearDownEglContextAndSurface(display, context, surface);
+TEST_P(GfxstreamEnd2EndGlTest, ProgramBinaryWithAHB) {
+ const uint32_t width = 2;
+ const uint32_t height = 2;
+ auto ahb =
+ GL_ASSERT(ScopedAHardwareBuffer::Allocate(*mGralloc, width, height, DRM_FORMAT_ABGR8888));
+
+ {
+ uint8_t* mapped = GL_ASSERT(ahb.Lock());
+ uint32_t pos = 0;
+ for (uint32_t h = 0; h < height; h++) {
+ for (uint32_t w = 0; w < width; w++) {
+ mapped[pos++] = 0;
+ mapped[pos++] = 0;
+ mapped[pos++] = 128;
+ mapped[pos++] = 255;
+ }
+ }
+ ahb.Unlock();
+ }
+
+ const EGLint ahbImageAttribs[] = {
+ // clang-format off
+ EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
+ EGL_NONE,
+ // clang-format on
+ };
+ EGLImageKHR ahbImage = mGl->eglCreateImageKHR(mDisplay, EGL_NO_CONTEXT,
+ EGL_NATIVE_BUFFER_ANDROID, ahb, ahbImageAttribs);
+ ASSERT_THAT(ahbImage, Not(Eq(EGL_NO_IMAGE_KHR)));
+
+ ScopedGlTexture ahbTexture(*mGl);
+ mGl->glBindTexture(GL_TEXTURE_EXTERNAL_OES, ahbTexture);
+ mGl->glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ mGl->glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ mGl->glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, ahbImage);
+ ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
+
+ GLenum programBinaryFormat = GL_NONE;
+ std::vector<uint8_t> programBinaryData;
+ {
+ const std::string vertSource = R"(\
+ #version 300 es
+
+ layout (location = 0) in vec2 pos;
+ layout (location = 1) in vec2 tex;
+
+ out vec2 vTex;
+
+ void main() {
+ gl_Position = vec4(pos, 0.0, 1.0);
+ vTex = tex;
+ })";
+
+ const std::string fragSource = R"(\
+ #version 300 es
+
+ precision highp float;
+
+ uniform float uMultiplier;
+ uniform sampler2D uTexture;
+
+ in vec2 vTex;
+
+ out vec4 oColor;
+
+ void main() {
+ oColor = texture(uTexture, vTex) * uMultiplier;
+ })";
+
+ ScopedGlProgram program = GL_ASSERT(SetUpProgram(vertSource, fragSource));
+
+ GLint programBinaryLength = 0;
+ mGl->glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &programBinaryLength);
+ ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
+
+ programBinaryData.resize(programBinaryLength);
+
+ GLint readProgramBinaryLength = 0;
+ mGl->glGetProgramBinary(program, programBinaryLength, &readProgramBinaryLength,
+ &programBinaryFormat, programBinaryData.data());
+ ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
+ ASSERT_THAT(programBinaryLength, Eq(readProgramBinaryLength));
+ }
+
+ ScopedGlProgram program = GL_ASSERT(SetUpProgram(programBinaryFormat, programBinaryData));
+ ASSERT_THAT(program, Not(Eq(0)));
+
+ GLint textureUniformLoc = mGl->glGetUniformLocation(program, "uTexture");
+ ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
+ ASSERT_THAT(textureUniformLoc, Not(Eq(-1)));
+
+ GLint multiplierUniformLoc = mGl->glGetUniformLocation(program, "uMultiplier");
+ ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
+ ASSERT_THAT(multiplierUniformLoc, Not(Eq(-1)));
+
+ const GLsizei kFramebufferWidth = 4;
+ const GLsizei kFramebufferHeight = 4;
+ ScopedGlFramebuffer framebuffer(*mGl);
+ mGl->glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
+ ScopedGlTexture framebufferTexture(*mGl);
+ mGl->glBindTexture(GL_TEXTURE_2D, framebufferTexture);
+ mGl->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kFramebufferWidth, kFramebufferHeight, 0, GL_RGBA,
+ GL_UNSIGNED_BYTE, nullptr);
+ mGl->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ framebufferTexture, 0);
+ ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
+ ASSERT_THAT(mGl->glCheckFramebufferStatus(GL_FRAMEBUFFER), Eq(GL_FRAMEBUFFER_COMPLETE));
+ mGl->glBindTexture(GL_TEXTURE_2D, 0);
+ ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
+
+ struct VertexAttributes {
+ float pos[2];
+ float tex[2];
+ };
+ const VertexAttributes vertexAttrs[] = {
+ // clang-format off
+ { { -1.0f, -1.0f,}, { 0.0f, 0.0f }, },
+ { { 3.0f, -1.0f,}, { 2.0f, 0.0f }, },
+ { { -1.0f, 3.0f,}, { 0.0f, 2.0f }, },
+ // clang-format on
+ };
+ ScopedGlBuffer buffer(*mGl);
+ mGl->glBindBuffer(GL_ARRAY_BUFFER, buffer);
+ mGl->glBufferData(GL_ARRAY_BUFFER, sizeof(vertexAttrs), vertexAttrs, GL_STATIC_DRAW);
+
+ mGl->glUseProgram(program);
+ ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
+
+ mGl->glBindBuffer(GL_ARRAY_BUFFER, buffer);
+ mGl->glEnableVertexAttribArray(0);
+ mGl->glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(VertexAttributes),
+ (GLvoid*)offsetof(VertexAttributes, pos));
+ mGl->glEnableVertexAttribArray(1);
+ mGl->glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(VertexAttributes),
+ (GLvoid*)offsetof(VertexAttributes, tex));
+ ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
+
+ mGl->glActiveTexture(GL_TEXTURE0);
+ mGl->glBindTexture(GL_TEXTURE_2D, ahbTexture);
+ mGl->glUniform1i(textureUniformLoc, 0);
+ ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
+
+ mGl->glUniform1f(multiplierUniformLoc, 2.0f);
+ ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
+
+ mGl->glDrawArrays(GL_TRIANGLES, 0, 3);
+ ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
+
+ for (int x = 0; x < kFramebufferWidth; x++) {
+ for (int y = 0; y < kFramebufferHeight; y++) {
+ EXPECT_THAT(GetPixelAt(x, y), IsOkWithRGBA(0, 0, 255, 255));
+ }
+ }
+
+ mGl->glBindFramebuffer(GL_FRAMEBUFFER, 0);
+}
+
+TEST_P(GfxstreamEnd2EndGlTest, ProgramBinaryWithTexture) {
+ const GLsizei kTextureWidth = 2;
+ const GLsizei kTextureHeight = 2;
+ const GLubyte kTextureData[16] = {
+ // clang-format off
+ 0, 0, 128, 255, 0, 0, 128, 255,
+
+ 0, 0, 128, 255, 0, 0, 128, 255,
+ // clang-format on
+ };
+ ScopedGlTexture texture(*mGl);
+ mGl->glBindTexture(GL_TEXTURE_2D, texture);
+ mGl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ mGl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ mGl->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kTextureWidth, kTextureHeight, 0, GL_RGBA,
+ GL_UNSIGNED_BYTE, kTextureData);
+ ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
+
+ GLenum programBinaryFormat = GL_NONE;
+ std::vector<uint8_t> programBinaryData;
+ {
+ const std::string vertSource = R"(\
+ #version 300 es
+
+ layout (location = 0) in vec2 pos;
+ layout (location = 1) in vec2 tex;
+
+ out vec2 vTex;
+
+ void main() {
+ gl_Position = vec4(pos, 0.0, 1.0);
+ vTex = tex;
+ })";
+
+ const std::string fragSource = R"(\
+ #version 300 es
+
+ precision highp float;
+
+ uniform float uMultiplier;
+ uniform sampler2D uTexture;
+
+ in vec2 vTex;
+
+ out vec4 oColor;
+
+ void main() {
+ oColor = texture(uTexture, vTex) * uMultiplier;
+ })";
+
+ ScopedGlProgram program = GL_ASSERT(SetUpProgram(vertSource, fragSource));
+
+ GLint programBinaryLength = 0;
+ mGl->glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &programBinaryLength);
+ ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
+
+ programBinaryData.resize(programBinaryLength);
+
+ GLint readProgramBinaryLength = 0;
+ mGl->glGetProgramBinary(program, programBinaryLength, &readProgramBinaryLength,
+ &programBinaryFormat, programBinaryData.data());
+ ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
+ ASSERT_THAT(programBinaryLength, Eq(readProgramBinaryLength));
+ }
+
+ ScopedGlProgram program = GL_ASSERT(SetUpProgram(programBinaryFormat, programBinaryData));
+ ASSERT_THAT(program, Not(Eq(0)));
+
+ GLint textureUniformLoc = mGl->glGetUniformLocation(program, "uTexture");
+ ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
+ ASSERT_THAT(textureUniformLoc, Not(Eq(-1)));
+
+ GLint multiplierUniformLoc = mGl->glGetUniformLocation(program, "uMultiplier");
+ ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
+ ASSERT_THAT(multiplierUniformLoc, Not(Eq(-1)));
+
+ const GLsizei kFramebufferWidth = 4;
+ const GLsizei kFramebufferHeight = 4;
+ ScopedGlFramebuffer framebuffer(*mGl);
+ mGl->glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
+ ScopedGlTexture framebufferTexture(*mGl);
+ mGl->glBindTexture(GL_TEXTURE_2D, framebufferTexture);
+ mGl->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kFramebufferWidth, kFramebufferHeight, 0, GL_RGBA,
+ GL_UNSIGNED_BYTE, nullptr);
+ mGl->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ framebufferTexture, 0);
+ ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
+ ASSERT_THAT(mGl->glCheckFramebufferStatus(GL_FRAMEBUFFER), Eq(GL_FRAMEBUFFER_COMPLETE));
+ mGl->glBindTexture(GL_TEXTURE_2D, 0);
+ ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
+
+ struct VertexAttributes {
+ float pos[2];
+ float tex[2];
+ };
+ const VertexAttributes vertexAttrs[] = {
+ // clang-format off
+ { { -1.0f, -1.0f,}, { 0.0f, 0.0f }, },
+ { { 3.0f, -1.0f,}, { 2.0f, 0.0f }, },
+ { { -1.0f, 3.0f,}, { 0.0f, 2.0f }, },
+ // clang-format on
+ };
+ ScopedGlBuffer buffer(*mGl);
+ mGl->glBindBuffer(GL_ARRAY_BUFFER, buffer);
+ mGl->glBufferData(GL_ARRAY_BUFFER, sizeof(vertexAttrs), vertexAttrs, GL_STATIC_DRAW);
+
+ mGl->glUseProgram(program);
+ ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
+
+ mGl->glBindBuffer(GL_ARRAY_BUFFER, buffer);
+ mGl->glEnableVertexAttribArray(0);
+ mGl->glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(VertexAttributes),
+ (GLvoid*)offsetof(VertexAttributes, pos));
+ mGl->glEnableVertexAttribArray(1);
+ mGl->glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(VertexAttributes),
+ (GLvoid*)offsetof(VertexAttributes, tex));
+ ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
+
+ mGl->glActiveTexture(GL_TEXTURE0);
+ mGl->glBindTexture(GL_TEXTURE_2D, texture);
+ mGl->glUniform1i(textureUniformLoc, 0);
+ ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
+
+ mGl->glUniform1f(multiplierUniformLoc, 2.0f);
+ ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
+
+ mGl->glDrawArrays(GL_TRIANGLES, 0, 3);
+ ASSERT_THAT(mGl->glGetError(), Eq(GL_NO_ERROR));
+
+ for (int x = 0; x < kFramebufferWidth; x++) {
+ for (int y = 0; y < kFramebufferHeight; y++) {
+ EXPECT_THAT(GetPixelAt(x, y), IsOkWithRGBA(0, 0, 255, 255));
+ }
+ }
+
+ mGl->glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
INSTANTIATE_TEST_CASE_P(GfxstreamEnd2EndTests, GfxstreamEnd2EndGlTest,
diff --git a/common/end2end/GfxstreamEnd2EndTests.cpp b/common/end2end/GfxstreamEnd2EndTests.cpp
index 5d698b9..16dee00 100644
--- a/common/end2end/GfxstreamEnd2EndTests.cpp
+++ b/common/end2end/GfxstreamEnd2EndTests.cpp
@@ -83,7 +83,7 @@
return info.param.ToString();
}
-std::unique_ptr<GfxstreamEnd2EndTest::GuestGlDispatchTable> GfxstreamEnd2EndTest::SetupGuestGl() {
+std::unique_ptr<GuestGlDispatchTable> GfxstreamEnd2EndTest::SetupGuestGl() {
const std::filesystem::path testDirectory = gfxstream::guest::getProgramDirectory();
const std::string eglLibPath = (testDirectory / "libEGL_emulation_with_host.so").string();
const std::string gles2LibPath = (testDirectory / "libGLESv2_emulation_with_host.so").string();
@@ -117,11 +117,13 @@
LIST_RENDER_EGL_FUNCTIONS(LOAD_EGL_FUNCTION)
LIST_RENDER_EGL_EXTENSIONS_FUNCTIONS(LOAD_EGL_FUNCTION)
- #define LOAD_GLES2_FUNCTION(return_type, function_name, signature, callargs) \
- gl-> function_name = reinterpret_cast< return_type (*) signature >(eglGetAddr( #function_name )); \
- if (!gl-> function_name) { \
- gl-> function_name = reinterpret_cast< return_type (*) signature >(dlsym(gles2Lib, #function_name)); \
- }
+#define LOAD_GLES2_FUNCTION(return_type, function_name, signature, callargs) \
+ gl->function_name = \
+ reinterpret_cast<return_type(*) signature>(dlsym(gles2Lib, #function_name)); \
+ if (!gl->function_name) { \
+ gl->function_name = \
+ reinterpret_cast<return_type(*) signature>(eglGetAddr(#function_name)); \
+ }
LIST_GLES_FUNCTIONS(LOAD_GLES2_FUNCTION, LOAD_GLES2_FUNCTION)
@@ -290,91 +292,144 @@
ASSERT_THAT(mGl->eglDestroySurface(display, surface), IsTrue());
}
-GlExpected<GLuint> GfxstreamEnd2EndTest::SetUpShader(GLenum type, const std::string& source) {
- if (!mGl) {
- return android::base::unexpected("Gl not enabled for this test.");
- }
-
- GLuint shader = mGl->glCreateShader(type);
+GlExpected<ScopedGlShader> ScopedGlShader::MakeShader(GlDispatch& dispatch, GLenum type,
+ const std::string& source) {
+ GLuint shader = dispatch.glCreateShader(type);
if (!shader) {
return android::base::unexpected("Failed to create shader.");
}
const GLchar* sourceTyped = (const GLchar*)source.c_str();
const GLint sourceLength = source.size();
- mGl->glShaderSource(shader, 1, &sourceTyped, &sourceLength);
- mGl->glCompileShader(shader);
-
- GLenum err = mGl->glGetError();
- if (err != GL_NO_ERROR) {
- return android::base::unexpected("Failed to compile shader.");
- }
+ dispatch.glShaderSource(shader, 1, &sourceTyped, &sourceLength);
+ dispatch.glCompileShader(shader);
GLint compileStatus;
- mGl->glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus);
+ dispatch.glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus);
- if (compileStatus == GL_TRUE) {
- return shader;
- } else {
+ if (compileStatus != GL_TRUE) {
GLint errorLogLength = 0;
- mGl->glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &errorLogLength);
+ dispatch.glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &errorLogLength);
if (!errorLogLength) {
errorLogLength = 512;
}
std::vector<GLchar> errorLog(errorLogLength);
- mGl->glGetShaderInfoLog(shader, errorLogLength, &errorLogLength, errorLog.data());
+ dispatch.glGetShaderInfoLog(shader, errorLogLength, &errorLogLength, errorLog.data());
const std::string errorString = errorLogLength == 0 ? "" : errorLog.data();
ALOGE("Shader compilation failed with: \"%s\"", errorString.c_str());
- mGl->glDeleteShader(shader);
+ dispatch.glDeleteShader(shader);
return android::base::unexpected(errorString);
}
+
+ return ScopedGlShader(dispatch, shader);
}
-GlExpected<GLuint> GfxstreamEnd2EndTest::SetUpProgram(
- const std::string& vertSource,
- const std::string& fragSource) {
- auto vertResult = SetUpShader(GL_VERTEX_SHADER, vertSource);
- if (!vertResult.ok()) {
- return vertResult;
- }
- auto vertShader = vertResult.value();
+GlExpected<ScopedGlProgram> ScopedGlProgram::MakeProgram(GlDispatch& dispatch,
+ const std::string& vertSource,
+ const std::string& fragSource) {
+ auto vertShader = GL_EXPECT(ScopedGlShader::MakeShader(dispatch, GL_VERTEX_SHADER, vertSource));
+ auto fragShader =
+ GL_EXPECT(ScopedGlShader::MakeShader(dispatch, GL_FRAGMENT_SHADER, fragSource));
- auto fragResult = SetUpShader(GL_FRAGMENT_SHADER, fragSource);
- if (!fragResult.ok()) {
- return fragResult;
- }
- auto fragShader = fragResult.value();
-
- GLuint program = mGl->glCreateProgram();
- mGl->glAttachShader(program, vertShader);
- mGl->glAttachShader(program, fragShader);
- mGl->glLinkProgram(program);
- mGl->glDeleteShader(vertShader);
- mGl->glDeleteShader(fragShader);
+ GLuint program = dispatch.glCreateProgram();
+ dispatch.glAttachShader(program, vertShader);
+ dispatch.glAttachShader(program, fragShader);
+ dispatch.glLinkProgram(program);
GLint linkStatus;
- mGl->glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
- if (linkStatus == GL_TRUE) {
- return program;
- } else {
+ dispatch.glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
+ if (linkStatus != GL_TRUE) {
GLint errorLogLength = 0;
- mGl->glGetProgramiv(program, GL_INFO_LOG_LENGTH, &errorLogLength);
+ dispatch.glGetProgramiv(program, GL_INFO_LOG_LENGTH, &errorLogLength);
if (!errorLogLength) {
errorLogLength = 512;
}
std::vector<char> errorLog(errorLogLength, 0);
- mGl->glGetProgramInfoLog(program, errorLogLength, nullptr, errorLog.data());
+ dispatch.glGetProgramInfoLog(program, errorLogLength, nullptr, errorLog.data());
const std::string errorString = errorLogLength == 0 ? "" : errorLog.data();
ALOGE("Program link failed with: \"%s\"", errorString.c_str());
- mGl->glDeleteProgram(program);
+ dispatch.glDeleteProgram(program);
return android::base::unexpected(errorString);
}
+
+ return ScopedGlProgram(dispatch, program);
+}
+
+GlExpected<ScopedGlProgram> ScopedGlProgram::MakeProgram(
+ GlDispatch& dispatch, GLenum programBinaryFormat,
+ const std::vector<uint8_t>& programBinaryData) {
+ GLuint program = dispatch.glCreateProgram();
+ dispatch.glProgramBinary(program, programBinaryFormat, programBinaryData.data(),
+ programBinaryData.size());
+
+ GLint linkStatus;
+ dispatch.glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
+ if (linkStatus != GL_TRUE) {
+ GLint errorLogLength = 0;
+ dispatch.glGetProgramiv(program, GL_INFO_LOG_LENGTH, &errorLogLength);
+ if (!errorLogLength) {
+ errorLogLength = 512;
+ }
+
+ std::vector<char> errorLog(errorLogLength, 0);
+ dispatch.glGetProgramInfoLog(program, errorLogLength, nullptr, errorLog.data());
+
+ const std::string errorString = errorLogLength == 0 ? "" : errorLog.data();
+ ALOGE("Program link failed with: \"%s\"", errorString.c_str());
+
+ dispatch.glDeleteProgram(program);
+ return android::base::unexpected(errorString);
+ }
+
+ return ScopedGlProgram(dispatch, program);
+}
+
+GlExpected<ScopedAHardwareBuffer> ScopedAHardwareBuffer::Allocate(Gralloc& gralloc, uint32_t width,
+ uint32_t height,
+ uint32_t format) {
+ AHardwareBuffer* ahb = nullptr;
+ int status = gralloc.allocate(width, height, format, -1, &ahb);
+ if (status != 0) {
+ return android::base::unexpected(std::string("Failed to allocate AHB with width:") +
+ std::to_string(width) + std::string(" height:") +
+ std::to_string(height) + std::string(" format:") +
+ std::to_string(format));
+ }
+
+ return ScopedAHardwareBuffer(gralloc, ahb);
+}
+
+GlExpected<ScopedGlShader> GfxstreamEnd2EndTest::SetUpShader(GLenum type,
+ const std::string& source) {
+ if (!mGl) {
+ return android::base::unexpected("Gl not enabled for this test.");
+ }
+
+ return ScopedGlShader::MakeShader(*mGl, type, source);
+}
+
+GlExpected<ScopedGlProgram> GfxstreamEnd2EndTest::SetUpProgram(const std::string& vertSource,
+ const std::string& fragSource) {
+ if (!mGl) {
+ return android::base::unexpected("Gl not enabled for this test.");
+ }
+
+ return ScopedGlProgram::MakeProgram(*mGl, vertSource, fragSource);
+}
+
+GlExpected<ScopedGlProgram> GfxstreamEnd2EndTest::SetUpProgram(
+ GLenum programBinaryFormat, const std::vector<uint8_t>& programBinaryData) {
+ if (!mGl) {
+ return android::base::unexpected("Gl not enabled for this test.");
+ }
+
+ return ScopedGlProgram::MakeProgram(*mGl, programBinaryFormat, programBinaryData);
}
VkExpected<GfxstreamEnd2EndTest::TypicalVkTestEnvironment>
diff --git a/common/end2end/GfxstreamEnd2EndTests.h b/common/end2end/GfxstreamEnd2EndTests.h
index 34fd728..7b1ca12 100644
--- a/common/end2end/GfxstreamEnd2EndTests.h
+++ b/common/end2end/GfxstreamEnd2EndTests.h
@@ -89,6 +89,24 @@
template <typename GlType>
using GlExpected = android::base::expected<GlType, std::string>;
+#define GL_ASSERT(x) \
+ ({ \
+ auto gl_result = (x); \
+ if (!gl_result.ok()) { \
+ ASSERT_THAT(gl_result, IsOk()); \
+ } \
+ std::move(gl_result.value()); \
+ })
+
+#define GL_EXPECT(x) \
+ ({ \
+ auto gl_result = (x); \
+ if (!gl_result.ok()) { \
+ return android::base::unexpected(gl_result.error()); \
+ } \
+ std::move(gl_result.value()); \
+ })
+
template <typename VkType>
using VkExpected = android::base::expected<VkType, vkhpp::Result>;
@@ -142,6 +160,219 @@
std::move(vkhpp_result_value.value); \
})
+struct GuestGlDispatchTable {
+#define DECLARE_EGL_FUNCTION(return_type, function_name, signature) \
+ return_type(*function_name) signature = nullptr;
+
+#define DECLARE_GLES_FUNCTION(return_type, function_name, signature, args) \
+ return_type(*function_name) signature = nullptr;
+
+ LIST_RENDER_EGL_FUNCTIONS(DECLARE_EGL_FUNCTION)
+ LIST_RENDER_EGL_EXTENSIONS_FUNCTIONS(DECLARE_EGL_FUNCTION)
+ LIST_GLES_FUNCTIONS(DECLARE_GLES_FUNCTION, DECLARE_GLES_FUNCTION)
+};
+
+class ScopedGlType {
+ public:
+ using GlDispatch = GuestGlDispatchTable;
+ using GlDispatchGenFunc = void (*GuestGlDispatchTable::*)(GLsizei, GLuint*);
+ using GlDispatchDelFunc = void (*GuestGlDispatchTable::*)(GLsizei, const GLuint*);
+
+ ScopedGlType() {}
+
+ ScopedGlType(GlDispatch& glDispatch, GlDispatchGenFunc glGenFunc, GlDispatchDelFunc glDelFunc)
+ : mGlDispatch(&glDispatch), mGlGenFunc(glGenFunc), mGlDelFunc(glDelFunc) {
+ (mGlDispatch->*mGlGenFunc)(1, &mHandle);
+ }
+
+ ScopedGlType(const ScopedGlType& rhs) = delete;
+ ScopedGlType& operator=(const ScopedGlType& rhs) = delete;
+
+ ScopedGlType(ScopedGlType&& rhs)
+ : mGlDispatch(rhs.mGlDispatch),
+ mGlGenFunc(rhs.mGlGenFunc),
+ mGlDelFunc(rhs.mGlDelFunc),
+ mHandle(rhs.mHandle) {
+ rhs.mHandle = 0;
+ }
+
+ ScopedGlType& operator=(ScopedGlType&& rhs) {
+ mGlDispatch = rhs.mGlDispatch;
+ mGlGenFunc = rhs.mGlGenFunc;
+ mGlDelFunc = rhs.mGlDelFunc;
+ std::swap(mHandle, rhs.mHandle);
+ return *this;
+ }
+
+ ~ScopedGlType() {
+ if (mHandle != 0) {
+ (mGlDispatch->*mGlDelFunc)(1, &mHandle);
+ mHandle = 0;
+ }
+ }
+
+ operator GLuint() { return mHandle; }
+ operator GLuint() const { return mHandle; }
+
+ private:
+ GlDispatch* mGlDispatch = nullptr;
+ GlDispatchGenFunc mGlGenFunc = nullptr;
+ GlDispatchDelFunc mGlDelFunc = nullptr;
+ GLuint mHandle = 0;
+};
+
+class ScopedGlBuffer : public ScopedGlType {
+ public:
+ ScopedGlBuffer(GlDispatch& dispatch)
+ : ScopedGlType(dispatch, &GlDispatch::glGenBuffers, &GlDispatch::glDeleteBuffers) {}
+};
+
+class ScopedGlTexture : public ScopedGlType {
+ public:
+ ScopedGlTexture(GlDispatch& dispatch)
+ : ScopedGlType(dispatch, &GlDispatch::glGenTextures, &GlDispatch::glDeleteTextures) {}
+};
+
+class ScopedGlFramebuffer : public ScopedGlType {
+ public:
+ ScopedGlFramebuffer(GlDispatch& dispatch)
+ : ScopedGlType(dispatch, &GlDispatch::glGenFramebuffers,
+ &GlDispatch::glDeleteFramebuffers) {}
+};
+
+class ScopedGlShader {
+ public:
+ using GlDispatch = GuestGlDispatchTable;
+
+ ScopedGlShader() = default;
+
+ ScopedGlShader(const ScopedGlShader& rhs) = delete;
+ ScopedGlShader& operator=(const ScopedGlShader& rhs) = delete;
+
+ static GlExpected<ScopedGlShader> MakeShader(GlDispatch& dispatch, GLenum type,
+ const std::string& source);
+
+ ScopedGlShader(ScopedGlShader&& rhs) : mGlDispatch(rhs.mGlDispatch), mHandle(rhs.mHandle) {
+ rhs.mHandle = 0;
+ }
+
+ ScopedGlShader& operator=(ScopedGlShader&& rhs) {
+ mGlDispatch = rhs.mGlDispatch;
+ std::swap(mHandle, rhs.mHandle);
+ return *this;
+ }
+
+ ~ScopedGlShader() {
+ if (mHandle != 0) {
+ mGlDispatch->glDeleteShader(mHandle);
+ mHandle = 0;
+ }
+ }
+
+ operator GLuint() { return mHandle; }
+ operator GLuint() const { return mHandle; }
+
+ private:
+ ScopedGlShader(GlDispatch& dispatch, GLuint handle) : mGlDispatch(&dispatch), mHandle(handle) {}
+
+ GlDispatch* mGlDispatch = nullptr;
+ GLuint mHandle = 0;
+};
+
+class ScopedGlProgram {
+ public:
+ using GlDispatch = GuestGlDispatchTable;
+
+ ScopedGlProgram() = default;
+
+ ScopedGlProgram(const ScopedGlProgram& rhs) = delete;
+ ScopedGlProgram& operator=(const ScopedGlProgram& rhs) = delete;
+
+ static GlExpected<ScopedGlProgram> MakeProgram(GlDispatch& dispatch,
+ const std::string& vertShader,
+ const std::string& fragShader);
+
+ static GlExpected<ScopedGlProgram> MakeProgram(GlDispatch& dispatch, GLenum programBinaryFormat,
+ const std::vector<uint8_t>& programBinaryData);
+
+ ScopedGlProgram(ScopedGlProgram&& rhs) : mGlDispatch(rhs.mGlDispatch), mHandle(rhs.mHandle) {
+ rhs.mHandle = 0;
+ }
+
+ ScopedGlProgram& operator=(ScopedGlProgram&& rhs) {
+ mGlDispatch = rhs.mGlDispatch;
+ std::swap(mHandle, rhs.mHandle);
+ return *this;
+ }
+
+ ~ScopedGlProgram() {
+ if (mHandle != 0) {
+ mGlDispatch->glDeleteProgram(mHandle);
+ mHandle = 0;
+ }
+ }
+
+ operator GLuint() { return mHandle; }
+ operator GLuint() const { return mHandle; }
+
+ private:
+ ScopedGlProgram(GlDispatch& dispatch, GLuint handle)
+ : mGlDispatch(&dispatch), mHandle(handle) {}
+
+ GlDispatch* mGlDispatch = nullptr;
+ GLuint mHandle = 0;
+};
+
+class ScopedAHardwareBuffer {
+ public:
+ ScopedAHardwareBuffer() = default;
+
+ static GlExpected<ScopedAHardwareBuffer> Allocate(Gralloc& gralloc, uint32_t width,
+ uint32_t height, uint32_t format);
+
+ ScopedAHardwareBuffer(const ScopedAHardwareBuffer& rhs) = delete;
+ ScopedAHardwareBuffer& operator=(const ScopedAHardwareBuffer& rhs) = delete;
+
+ ScopedAHardwareBuffer(ScopedAHardwareBuffer&& rhs)
+ : mGralloc(rhs.mGralloc), mHandle(rhs.mHandle) {
+ rhs.mHandle = nullptr;
+ }
+
+ ScopedAHardwareBuffer& operator=(ScopedAHardwareBuffer&& rhs) {
+ mGralloc = rhs.mGralloc;
+ std::swap(mHandle, rhs.mHandle);
+ return *this;
+ }
+
+ ~ScopedAHardwareBuffer() {
+ if (mHandle != nullptr) {
+ mGralloc->release(mHandle);
+ mHandle = 0;
+ }
+ }
+
+ GlExpected<uint8_t*> Lock() {
+ uint8_t* mapped = nullptr;
+ int status = mGralloc->lock(mHandle, &mapped);
+ if (status != 0) {
+ return android::base::unexpected("Failed to lock AHB");
+ }
+ return mapped;
+ }
+
+ void Unlock() { mGralloc->unlock(mHandle); }
+
+ operator AHardwareBuffer*() { return mHandle; }
+ operator AHardwareBuffer*() const { return mHandle; }
+
+ private:
+ ScopedAHardwareBuffer(Gralloc& gralloc, AHardwareBuffer* handle)
+ : mGralloc(&gralloc), mHandle(handle) {}
+
+ Gralloc* mGralloc = nullptr;
+ AHardwareBuffer* mHandle = nullptr;
+};
+
enum class GfxstreamTransport {
kVirtioGpuAsg,
kVirtioGpuPipe,
@@ -160,19 +391,7 @@
std::string GetTestName(const ::testing::TestParamInfo<TestParams>& info);
class GfxstreamEnd2EndTest : public ::testing::TestWithParam<TestParams> {
- protected:
- struct GuestGlDispatchTable {
- #define DECLARE_EGL_FUNCTION(return_type, function_name, signature) \
- return_type (*function_name) signature = nullptr;
-
- #define DECLARE_GLES_FUNCTION(return_type, function_name, signature, args) \
- return_type (*function_name) signature = nullptr;
-
- LIST_RENDER_EGL_FUNCTIONS(DECLARE_EGL_FUNCTION)
- LIST_RENDER_EGL_EXTENSIONS_FUNCTIONS(DECLARE_EGL_FUNCTION)
- LIST_GLES_FUNCTIONS(DECLARE_GLES_FUNCTION, DECLARE_GLES_FUNCTION)
- };
-
+ public:
std::unique_ptr<GuestGlDispatchTable> SetupGuestGl();
std::unique_ptr<vkhpp::DynamicLoader> SetupGuestVk();
@@ -193,10 +412,13 @@
EGLContext context,
EGLSurface surface);
- GlExpected<GLuint> SetUpShader(GLenum type, const std::string& source);
+ GlExpected<ScopedGlShader> SetUpShader(GLenum type, const std::string& source);
- GlExpected<GLuint> SetUpProgram(const std::string& vertSource,
- const std::string& fragSource);
+ GlExpected<ScopedGlProgram> SetUpProgram(const std::string& vertSource,
+ const std::string& fragSource);
+
+ GlExpected<ScopedGlProgram> SetUpProgram(GLenum programBinaryFormat,
+ const std::vector<uint8_t>& programBinaryData);
struct TypicalVkTestEnvironment {
vkhpp::UniqueInstance instance;
diff --git a/common/utils/Android.bp b/common/utils/Android.bp
index 9d8040b..35d823b 100644
--- a/common/utils/Android.bp
+++ b/common/utils/Android.bp
@@ -1,4 +1,3 @@
-
package {
// See: http://go/android-license-faq
default_applicable_licenses: ["hardware_google_gfxstream_license"],
diff --git a/guest/GLESv2_enc/GL2Encoder.cpp b/guest/GLESv2_enc/GL2Encoder.cpp
index 937a18a..7806906 100755
--- a/guest/GLESv2_enc/GL2Encoder.cpp
+++ b/guest/GLESv2_enc/GL2Encoder.cpp
@@ -15,21 +15,21 @@
*/
#include "GL2Encoder.h"
-#include "GLESv2Validation.h"
-#include "GLESTextureUtils.h"
-
-#include <string>
-#include <map>
-
-#include <assert.h>
-#include <ctype.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <GLES2/gl2platform.h>
-
#include <GLES3/gl3.h>
#include <GLES3/gl31.h>
+#include <assert.h>
+#include <ctype.h>
+
+#include <map>
+#include <string>
+
+#include "EncoderDebug.h"
+#include "GLESTextureUtils.h"
+#include "GLESv2Validation.h"
using gfxstream::guest::BufferData;
using gfxstream::guest::ChecksumCalculator;
@@ -1939,23 +1939,11 @@
ctx->glFinishRoundTrip(self);
}
-void GL2Encoder::s_glLinkProgram(void * self, GLuint program)
-{
- GL2Encoder *ctx = (GL2Encoder *)self;
- bool isProgram = ctx->m_shared->isProgram(program);
- SET_ERROR_IF(!isProgram && !ctx->m_shared->isShader(program), GL_INVALID_VALUE);
- SET_ERROR_IF(!isProgram, GL_INVALID_OPERATION);
-
- if (program == ctx->m_state->currentProgram() ||
- (!ctx->m_state->currentProgram() &&
- (program == ctx->m_state->currentShaderProgram()))) {
- SET_ERROR_IF(ctx->m_state->getTransformFeedbackActive(), GL_INVALID_OPERATION);
- }
-
- ctx->m_glLinkProgram_enc(self, program);
+void GL2Encoder::updateProgramInfoAfterLink(GLuint program) {
+ GL2Encoder* ctx = this;
GLint linkStatus = 0;
- ctx->m_glGetProgramiv_enc(self, program, GL_LINK_STATUS, &linkStatus);
+ ctx->m_glGetProgramiv_enc(ctx, program, GL_LINK_STATUS, &linkStatus);
ctx->m_shared->setProgramLinkStatus(program, linkStatus);
if (!linkStatus) {
return;
@@ -1964,15 +1952,15 @@
// get number of active uniforms and attributes in the program
GLint numUniforms=0;
GLint numAttributes=0;
- ctx->m_glGetProgramiv_enc(self, program, GL_ACTIVE_UNIFORMS, &numUniforms);
- ctx->m_glGetProgramiv_enc(self, program, GL_ACTIVE_ATTRIBUTES, &numAttributes);
+ ctx->m_glGetProgramiv_enc(ctx, program, GL_ACTIVE_UNIFORMS, &numUniforms);
+ ctx->m_glGetProgramiv_enc(ctx, program, GL_ACTIVE_ATTRIBUTES, &numAttributes);
ctx->m_shared->initProgramData(program,numUniforms,numAttributes);
//get the length of the longest uniform name
GLint maxLength=0;
GLint maxAttribLength=0;
- ctx->m_glGetProgramiv_enc(self, program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxLength);
- ctx->m_glGetProgramiv_enc(self, program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxAttribLength);
+ ctx->m_glGetProgramiv_enc(ctx, program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxLength);
+ ctx->m_glGetProgramiv_enc(ctx, program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxAttribLength);
GLint size;
GLenum type;
@@ -1982,14 +1970,14 @@
//for each active uniform, get its size and starting location.
for (GLint i=0 ; i<numUniforms ; ++i)
{
- ctx->m_glGetActiveUniform_enc(self, program, i, maxLength, NULL, &size, &type, name);
- location = ctx->m_glGetUniformLocation_enc(self, program, name);
+ ctx->m_glGetActiveUniform_enc(ctx, program, i, maxLength, NULL, &size, &type, name);
+ location = ctx->m_glGetUniformLocation_enc(ctx, program, name);
ctx->m_shared->setProgramIndexInfo(program, i, location, size, type, name);
}
for (GLint i = 0; i < numAttributes; ++i) {
- ctx->m_glGetActiveAttrib_enc(self, program, i, maxAttribLength, NULL, &size, &type, name);
- location = ctx->m_glGetAttribLocation_enc(self, program, name);
+ ctx->m_glGetActiveAttrib_enc(ctx, program, i, maxAttribLength, NULL, &size, &type, name);
+ location = ctx->m_glGetAttribLocation_enc(ctx, program, name);
ctx->m_shared->setProgramAttribInfo(program, i, location, size, type, name);
}
@@ -2006,6 +1994,22 @@
delete[] name;
}
+void GL2Encoder::s_glLinkProgram(void* self, GLuint program) {
+ GL2Encoder* ctx = (GL2Encoder*)self;
+ bool isProgram = ctx->m_shared->isProgram(program);
+ SET_ERROR_IF(!isProgram && !ctx->m_shared->isShader(program), GL_INVALID_VALUE);
+ SET_ERROR_IF(!isProgram, GL_INVALID_OPERATION);
+
+ if (program == ctx->m_state->currentProgram() ||
+ (!ctx->m_state->currentProgram() && (program == ctx->m_state->currentShaderProgram()))) {
+ SET_ERROR_IF(ctx->m_state->getTransformFeedbackActive(), GL_INVALID_OPERATION);
+ }
+
+ ctx->m_glLinkProgram_enc(self, program);
+
+ ctx->updateProgramInfoAfterLink(program);
+}
+
#define VALIDATE_PROGRAM_NAME(program) \
bool isShaderOrProgramObject = \
ctx->m_shared->isShaderOrProgramObject(program); \
@@ -6355,6 +6359,8 @@
SET_ERROR_IF(~0 == binaryFormat, GL_INVALID_ENUM);
ctx->m_glProgramBinary_enc(self, program, binaryFormat, binary, length);
+
+ ctx->updateProgramInfoAfterLink(program);
}
void GL2Encoder::s_glGetSamplerParameterfv(void *self, GLuint sampler, GLenum pname, GLfloat* params) {
diff --git a/guest/GLESv2_enc/GL2Encoder.h b/guest/GLESv2_enc/GL2Encoder.h
index 8c364a8..b1fde1b 100644
--- a/guest/GLESv2_enc/GL2Encoder.h
+++ b/guest/GLESv2_enc/GL2Encoder.h
@@ -43,32 +43,20 @@
class GL2Encoder : public gl2_encoder_context_t {
public:
- GL2Encoder(gfxstream::guest::IOStream *stream,
- gfxstream::guest::ChecksumCalculator* protocol);
- virtual ~GL2Encoder();
- const Extensions& getExtensions() const { return m_extensions; }
- void setDrawCallFlushInterval(uint32_t interval) {
- m_drawCallFlushInterval = interval;
- }
- void setHasAsyncUnmapBuffer(int version) {
- m_hasAsyncUnmapBuffer = version;
- }
- void setHasSyncBufferData(bool value) {
- m_hasSyncBufferData = value;
- }
- void setNoHostError(bool noHostError) {
- m_noHostError = noHostError;
- }
- void setClientState(gfxstream::guest::GLClientState *state) {
- m_state = state;
- }
- void setVersion(int major, int minor,
- int deviceMajor, int deviceMinor) {
- m_currMajorVersion = major;
- m_currMinorVersion = minor;
- m_deviceMajorVersion = deviceMajor;
- m_deviceMinorVersion = deviceMinor;
- }
+ GL2Encoder(gfxstream::guest::IOStream* stream, gfxstream::guest::ChecksumCalculator* protocol);
+ virtual ~GL2Encoder();
+ const Extensions& getExtensions() const { return m_extensions; }
+ void setDrawCallFlushInterval(uint32_t interval) { m_drawCallFlushInterval = interval; }
+ void setHasAsyncUnmapBuffer(int version) { m_hasAsyncUnmapBuffer = version; }
+ void setHasSyncBufferData(bool value) { m_hasSyncBufferData = value; }
+ void setNoHostError(bool noHostError) { m_noHostError = noHostError; }
+ void setClientState(gfxstream::guest::GLClientState* state) { m_state = state; }
+ void setVersion(int major, int minor, int deviceMajor, int deviceMinor) {
+ m_currMajorVersion = major;
+ m_currMinorVersion = minor;
+ m_deviceMajorVersion = deviceMajor;
+ m_deviceMinorVersion = deviceMinor;
+ }
void setClientStateMakeCurrent(gfxstream::guest::GLClientState *state,
int majorVersion,
int minorVersion,
@@ -202,6 +190,8 @@
void updateHostTexture2DBindingsFromProgramData(GLuint program);
bool texture2DNeedsOverride(GLenum target) const;
+ void updateProgramInfoAfterLink(GLuint program);
+
// Utility classes for safe queries that
// need access to private class members
class ErrorUpdater;
diff --git a/guest/android/GrallocEmulated.cpp b/guest/android/GrallocEmulated.cpp
index e6031b1..d171486 100644
--- a/guest/android/GrallocEmulated.cpp
+++ b/guest/android/GrallocEmulated.cpp
@@ -41,7 +41,7 @@
std::optional<uint32_t> DrmToVirglFormat(uint32_t drmFormat) {
switch (drmFormat) {
case DRM_FORMAT_ABGR8888:
- return VIRGL_FORMAT_B8G8R8A8_UNORM;
+ return VIRGL_FORMAT_R8G8B8A8_UNORM;
case DRM_FORMAT_BGR888:
return VIRGL_FORMAT_R8G8B8_UNORM;
case DRM_FORMAT_BGR565:
@@ -91,6 +91,33 @@
}
}
+int EmulatedAHardwareBuffer::lock(uint8_t** ptr) {
+ if (!mMapped) {
+ mMapped = mResource->createMapping();
+ if (!mMapped) {
+ ALOGE("Failed to lock EmulatedAHardwareBuffer: failed to create mapping.");
+ return -1;
+ }
+
+ mResource->transferFromHost(0, 0, mWidth, mHeight);
+ mResource->wait();
+ }
+
+ *ptr = (*mMapped)->asRawPtr();
+ return 0;
+}
+
+int EmulatedAHardwareBuffer::unlock() {
+ if (!mMapped) {
+ ALOGE("Failed to unlock EmulatedAHardwareBuffer: never locked?");
+ return -1;
+ }
+ mResource->transferToHost(0, 0, mWidth, mHeight);
+ mResource->wait();
+ mMapped.reset();
+ return 0;
+}
+
EmulatedGralloc::EmulatedGralloc() {}
uint32_t EmulatedGralloc::createColorBuffer(void*, int width, int height, uint32_t glFormat) {
@@ -152,6 +179,16 @@
rahb->release();
}
+int EmulatedGralloc::lock(AHardwareBuffer* ahb, uint8_t** ptr) {
+ auto* rahb = reinterpret_cast<EmulatedAHardwareBuffer*>(ahb);
+ return rahb->lock(ptr);
+}
+
+int EmulatedGralloc::unlock(AHardwareBuffer* ahb) {
+ auto* rahb = reinterpret_cast<EmulatedAHardwareBuffer*>(ahb);
+ return rahb->unlock();
+}
+
uint32_t EmulatedGralloc::getHostHandle(const native_handle_t* handle) {
const auto* ahb = reinterpret_cast<const EmulatedAHardwareBuffer*>(handle);
return ahb->getResourceId();
diff --git a/guest/android/GrallocEmulated.h b/guest/android/GrallocEmulated.h
index 8a48fef..cf1ba0f 100644
--- a/guest/android/GrallocEmulated.h
+++ b/guest/android/GrallocEmulated.h
@@ -14,10 +14,11 @@
#include <cstdint>
#include <memory>
+#include <optional>
#include <vector>
-#include "gfxstream/guest/Gralloc.h"
#include "VirtGpu.h"
+#include "gfxstream/guest/Gralloc.h"
namespace gfxstream {
@@ -48,11 +49,15 @@
void acquire();
void release();
+ int lock(uint8_t** ptr);
+ int unlock();
+
private:
uint32_t mRefCount;
uint32_t mWidth;
uint32_t mHeight;
VirtGpuBlobPtr mResource;
+ std::optional<VirtGpuBlobMappingPtr> mMapped;
};
class EmulatedGralloc : public Gralloc {
@@ -69,6 +74,9 @@
void acquire(AHardwareBuffer* ahb) override;
void release(AHardwareBuffer* ahb) override;
+ int lock(AHardwareBuffer* ahb, uint8_t** ptr) override;
+ int unlock(AHardwareBuffer* ahb) override;
+
uint32_t getHostHandle(const native_handle_t* handle) override;
uint32_t getHostHandle(const AHardwareBuffer* handle) override;
diff --git a/guest/android/GrallocGoldfish.cpp b/guest/android/GrallocGoldfish.cpp
index f07abde..ea5cdbf 100644
--- a/guest/android/GrallocGoldfish.cpp
+++ b/guest/android/GrallocGoldfish.cpp
@@ -43,6 +43,13 @@
void GoldfishGralloc::release(AHardwareBuffer* ahb) { AHardwareBuffer_release(ahb); }
+int GoldfishGralloc::lock(AHardwareBuffer* ahb, uint8_t** ptr) {
+ return AHardwareBuffer_lock(ahb, AHARDWAREBUFFER_USAGE_CPU_READ_RARELY, -1, nullptr,
+ reinterpret_cast<void**>(ptr));
+}
+
+int GoldfishGralloc::unlock(AHardwareBuffer* ahb) { return AHardwareBuffer_unlock(ahb, nullptr); }
+
uint32_t GoldfishGralloc::getHostHandle(native_handle_t const* handle) {
return cb_handle_t::from(handle)->hostHandle;
}
diff --git a/guest/android/GrallocGoldfish.h b/guest/android/GrallocGoldfish.h
index 560550f..f25eedf 100644
--- a/guest/android/GrallocGoldfish.h
+++ b/guest/android/GrallocGoldfish.h
@@ -28,6 +28,9 @@
void acquire(AHardwareBuffer* ahb) override;
void release(AHardwareBuffer* ahb) override;
+ int lock(AHardwareBuffer* ahb, uint8_t** ptr) override;
+ int unlock(AHardwareBuffer* ahb) override;
+
uint32_t getHostHandle(native_handle_t const* handle) override;
uint32_t getHostHandle(const AHardwareBuffer* handle) override;
diff --git a/guest/android/GrallocMinigbm.cpp b/guest/android/GrallocMinigbm.cpp
index a3daf43..85d7d9e 100644
--- a/guest/android/GrallocMinigbm.cpp
+++ b/guest/android/GrallocMinigbm.cpp
@@ -176,6 +176,13 @@
void MinigbmGralloc::release(AHardwareBuffer* ahb) { AHardwareBuffer_release(ahb); }
+int MinigbmGralloc::lock(AHardwareBuffer* ahb, uint8_t** ptr) {
+ return AHardwareBuffer_lock(ahb, AHARDWAREBUFFER_USAGE_CPU_READ_RARELY, -1, nullptr,
+ reinterpret_cast<void**>(ptr));
+}
+
+int MinigbmGralloc::unlock(AHardwareBuffer* ahb) { return AHardwareBuffer_unlock(ahb, nullptr); }
+
uint32_t MinigbmGralloc::getHostHandle(const native_handle_t* handle) {
struct drm_virtgpu_resource_info info;
if (!getVirtioGpuResourceInfo(m_fd, handle, &info)) {
diff --git a/guest/android/GrallocMinigbm.h b/guest/android/GrallocMinigbm.h
index c02aaeb..3ec1585 100644
--- a/guest/android/GrallocMinigbm.h
+++ b/guest/android/GrallocMinigbm.h
@@ -28,6 +28,9 @@
void acquire(AHardwareBuffer* ahb) override;
void release(AHardwareBuffer* ahb) override;
+ int lock(AHardwareBuffer* ahb, uint8_t** ptr) override;
+ int unlock(AHardwareBuffer* ahb) override;
+
uint32_t getHostHandle(native_handle_t const* handle) override;
uint32_t getHostHandle(const AHardwareBuffer* handle) override;
diff --git a/guest/android/include/gfxstream/guest/Gralloc.h b/guest/android/include/gfxstream/guest/Gralloc.h
index 5eb9139..ff281df 100644
--- a/guest/android/include/gfxstream/guest/Gralloc.h
+++ b/guest/android/include/gfxstream/guest/Gralloc.h
@@ -41,6 +41,9 @@
virtual int allocate(uint32_t width, uint32_t height, uint32_t format, uint64_t usage,
AHardwareBuffer** outputAhb) = 0;
+ virtual int lock(AHardwareBuffer* ahb, uint8_t** ptr) = 0;
+ virtual int unlock(AHardwareBuffer* ahb) = 0;
+
virtual const native_handle_t* getNativeHandle(const AHardwareBuffer* ahb) = 0;
virtual uint32_t getHostHandle(const native_handle_t* handle) = 0;
diff --git a/guest/platform/include/VirtGpu.h b/guest/platform/include/VirtGpu.h
index db5e2af..b9e039a 100644
--- a/guest/platform/include/VirtGpu.h
+++ b/guest/platform/include/VirtGpu.h
@@ -141,8 +141,15 @@
virtual VirtGpuBlobMappingPtr createMapping(void) = 0;
virtual int exportBlob(struct VirtGpuExternalHandle& handle) = 0;
- virtual int transferFromHost(uint32_t offset, uint32_t size) = 0;
- virtual int transferToHost(uint32_t offset, uint32_t size) = 0;
+ virtual int transferFromHost(uint32_t x, uint32_t y, uint32_t w, uint32_t h) = 0;
+ virtual int transferFromHost(uint32_t offset, uint32_t size) {
+ return transferFromHost(offset, 0, size, 1);
+ }
+
+ virtual int transferToHost(uint32_t x, uint32_t y, uint32_t w, uint32_t h) = 0;
+ virtual int transferToHost(uint32_t offset, uint32_t size) {
+ return transferToHost(offset, 0, size, 1);
+ }
};
class VirtGpuBlobMapping {
diff --git a/guest/platform/linux/LinuxVirtGpu.h b/guest/platform/linux/LinuxVirtGpu.h
index 6515728..8533280 100644
--- a/guest/platform/linux/LinuxVirtGpu.h
+++ b/guest/platform/linux/LinuxVirtGpu.h
@@ -31,8 +31,8 @@
VirtGpuBlobMappingPtr createMapping(void) override;
int exportBlob(struct VirtGpuExternalHandle& handle) override;
- int transferFromHost(uint32_t offset, uint32_t size) override;
- int transferToHost(uint32_t offset, uint32_t size) override;
+ int transferFromHost(uint32_t x, uint32_t y, uint32_t w, uint32_t h) override;
+ int transferToHost(uint32_t x, uint32_t y, uint32_t w, uint32_t h) override;
private:
// Not owned. Really should use a ScopedFD for this, but doesn't matter since we have a
diff --git a/guest/platform/linux/LinuxVirtGpuBlob.cpp b/guest/platform/linux/LinuxVirtGpuBlob.cpp
index 9ba1adc..bbf3d36 100644
--- a/guest/platform/linux/LinuxVirtGpuBlob.cpp
+++ b/guest/platform/linux/LinuxVirtGpuBlob.cpp
@@ -109,14 +109,14 @@
return 0;
}
-int LinuxVirtGpuBlob::transferToHost(uint32_t offset, uint32_t size) {
+int LinuxVirtGpuBlob::transferToHost(uint32_t x, uint32_t y, uint32_t w, uint32_t h) {
int ret;
struct drm_virtgpu_3d_transfer_to_host xfer = {0};
- xfer.box.x = offset;
- xfer.box.y = 0;
- xfer.box.w = size;
- xfer.box.h = 1;
+ xfer.box.x = x;
+ xfer.box.y = y;
+ xfer.box.w = w;
+ xfer.box.h = h;
xfer.box.d = 1;
xfer.bo_handle = mBlobHandle;
@@ -129,14 +129,14 @@
return 0;
}
-int LinuxVirtGpuBlob::transferFromHost(uint32_t offset, uint32_t size) {
+int LinuxVirtGpuBlob::transferFromHost(uint32_t x, uint32_t y, uint32_t w, uint32_t h) {
int ret;
struct drm_virtgpu_3d_transfer_from_host xfer = {0};
- xfer.box.x = offset;
- xfer.box.y = 0;
- xfer.box.w = size;
- xfer.box.h = 1;
+ xfer.box.x = x;
+ xfer.box.y = y;
+ xfer.box.w = w;
+ xfer.box.h = h;
xfer.box.d = 1;
xfer.bo_handle = mBlobHandle;
diff --git a/guest/platform/rutabaga/RutabagaLayer.cpp b/guest/platform/rutabaga/RutabagaLayer.cpp
index eee5f10..f702e2b 100644
--- a/guest/platform/rutabaga/RutabagaLayer.cpp
+++ b/guest/platform/rutabaga/RutabagaLayer.cpp
@@ -101,8 +101,13 @@
int TransferFromHost(uint32_t contextId, uint32_t resourceId, uint32_t transferOffset,
uint32_t transferSize);
+ int TransferFromHost(uint32_t contextId, uint32_t resourceId, uint32_t x, uint32_t y,
+ uint32_t w, uint32_t h);
+
int TransferToHost(uint32_t contextId, uint32_t resourceId, uint32_t transferOffset,
uint32_t transferSize);
+ int TransferToHost(uint32_t contextId, uint32_t resourceId, uint32_t x, uint32_t y, uint32_t w,
+ uint32_t h);
std::optional<uint32_t> CreateBlob(uint32_t contextId, uint32_t blobMem, uint32_t blobFlags,
uint64_t blobId, uint64_t blobSize);
@@ -159,14 +164,18 @@
struct VirtioGpuTaskTransferToHost {
uint32_t contextId;
uint32_t resourceId;
- uint32_t transferOffset;
- uint32_t transferSize;
+ uint32_t x;
+ uint32_t y;
+ uint32_t w;
+ uint32_t h;
};
struct VirtioGpuTaskTransferFromHost {
uint32_t contextId;
uint32_t resourceId;
- uint32_t transferOffset;
- uint32_t transferSize;
+ uint32_t x;
+ uint32_t y;
+ uint32_t w;
+ uint32_t h;
};
struct VirtioGpuTaskUnrefResource {
uint32_t resourceId;
@@ -458,6 +467,12 @@
uint32_t resourceId,
uint32_t transferOffset,
uint32_t transferSize) {
+ return TransferFromHost(contextId, resourceId, transferOffset, 0, transferSize, 1);
+}
+
+int EmulatedVirtioGpu::EmulatedVirtioGpuImpl::TransferFromHost(uint32_t contextId,
+ uint32_t resourceId, uint32_t x,
+ uint32_t y, uint32_t w, uint32_t h) {
EmulatedResource* resource = GetResource(resourceId);
if (resource == nullptr) {
ALOGE("Failed to TransferFromHost() on resource %" PRIu32 ": not found.", resourceId);
@@ -467,8 +482,10 @@
VirtioGpuTaskTransferFromHost task = {
.contextId = contextId,
.resourceId = resourceId,
- .transferOffset = transferOffset,
- .transferSize = transferSize,
+ .x = x,
+ .y = y,
+ .w = w,
+ .h = h,
};
auto waitable = EnqueueVirtioGpuTask(contextId, std::move(task));
@@ -484,6 +501,12 @@
uint32_t resourceId,
uint32_t transferOffset,
uint32_t transferSize) {
+ return TransferToHost(contextId, resourceId, transferOffset, 0, transferSize, 1);
+}
+
+int EmulatedVirtioGpu::EmulatedVirtioGpuImpl::TransferToHost(uint32_t contextId,
+ uint32_t resourceId, uint32_t x,
+ uint32_t y, uint32_t w, uint32_t h) {
EmulatedResource* resource = GetResource(resourceId);
if (resource == nullptr) {
ALOGE("Failed to TransferFromHost() on resource %" PRIu32 ": not found.", resourceId);
@@ -493,8 +516,10 @@
VirtioGpuTaskTransferToHost task = {
.contextId = contextId,
.resourceId = resourceId,
- .transferOffset = transferOffset,
- .transferSize = transferSize,
+ .x = x,
+ .y = y,
+ .w = w,
+ .h = h,
};
auto waitable = EnqueueVirtioGpuTask(contextId, std::move(task));
@@ -800,7 +825,7 @@
}
resource->iovec.iov_base = task.resourceBytes;
- resource->iovec.iov_len = task.params.width;
+ resource->iovec.iov_len = task.params.width * task.params.height * 4;
struct rutabaga_iovecs vecs = {0};
vecs.iovecs = &resource->iovec;
@@ -864,9 +889,11 @@
void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::DoTask(VirtioGpuTaskTransferFromHost task) {
struct rutabaga_transfer transfer = {0};
- transfer.x = task.transferOffset;
- transfer.w = task.transferSize;
- transfer.h = 1;
+ transfer.x = task.x;
+ transfer.y = task.y;
+ transfer.z = 0;
+ transfer.w = task.w;
+ transfer.h = task.h;
transfer.d = 1;
int ret = rutabaga_resource_transfer_read(mRutabaga, task.contextId, task.resourceId, &transfer,
@@ -878,9 +905,11 @@
void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::DoTask(VirtioGpuTaskTransferToHost task) {
struct rutabaga_transfer transfer = {0};
- transfer.x = task.transferOffset;
- transfer.w = task.transferSize;
- transfer.h = 1;
+ transfer.x = task.x;
+ transfer.y = task.y;
+ transfer.z = 0;
+ transfer.w = task.w;
+ transfer.h = task.h;
transfer.d = 1;
int ret =
@@ -998,7 +1027,7 @@
instance = std::shared_ptr<EmulatedVirtioGpu>(new EmulatedVirtioGpu());
bool withGl = false;
- bool withVk = true;
+ bool withVk = false;
bool withVkSnapshots = false;
struct Option {
@@ -1065,11 +1094,21 @@
return mImpl->TransferFromHost(contextId, resourceId, offset, size);
}
+int EmulatedVirtioGpu::TransferFromHost(uint32_t contextId, uint32_t resourceId, uint32_t x,
+ uint32_t y, uint32_t w, uint32_t h) {
+ return mImpl->TransferFromHost(contextId, resourceId, x, y, w, h);
+}
+
int EmulatedVirtioGpu::TransferToHost(uint32_t contextId, uint32_t resourceId, uint32_t offset,
uint32_t size) {
return mImpl->TransferToHost(contextId, resourceId, offset, size);
}
+int EmulatedVirtioGpu::TransferToHost(uint32_t contextId, uint32_t resourceId, uint32_t x,
+ uint32_t y, uint32_t w, uint32_t h) {
+ return mImpl->TransferToHost(contextId, resourceId, x, y, w, h);
+}
+
std::optional<uint32_t> EmulatedVirtioGpu::CreateBlob(uint32_t contextId, uint32_t blobMem,
uint32_t blobFlags, uint64_t blobId,
uint64_t blobSize) {
diff --git a/guest/platform/rutabaga/RutabagaLayer.h b/guest/platform/rutabaga/RutabagaLayer.h
index d5a0032..9303a64 100644
--- a/guest/platform/rutabaga/RutabagaLayer.h
+++ b/guest/platform/rutabaga/RutabagaLayer.h
@@ -68,8 +68,13 @@
int TransferFromHost(uint32_t contextId, uint32_t resourceId, uint32_t transferOffset,
uint32_t transferSize);
+ int TransferFromHost(uint32_t contextId, uint32_t resourceId, uint32_t x, uint32_t y, uint32_t w,
+ uint32_t h);
+
int TransferToHost(uint32_t contextId, uint32_t resourceId, uint32_t transferOffset,
uint32_t transferSize);
+ int TransferToHost(uint32_t contextId, uint32_t resourceId, uint32_t x, uint32_t y, uint32_t w,
+ uint32_t h);
void SignalEmulatedFence(int fenceId);
diff --git a/guest/platform/rutabaga/RutabagaVirtGpu.h b/guest/platform/rutabaga/RutabagaVirtGpu.h
index a47f60a..2e605e6 100644
--- a/guest/platform/rutabaga/RutabagaVirtGpu.h
+++ b/guest/platform/rutabaga/RutabagaVirtGpu.h
@@ -53,9 +53,12 @@
int wait() override;
int transferFromHost(uint32_t offset, uint32_t size) override;
- int transferToHost(uint32_t offset, uint32_t size) override;
+ int transferFromHost(uint32_t x, uint32_t y, uint32_t w, uint32_t h) override;
- private:
+ int transferToHost(uint32_t offset, uint32_t size) override;
+ int transferToHost(uint32_t x, uint32_t y, uint32_t w, uint32_t h) override;
+
+ private:
friend class RutabagaVirtGpuDevice;
enum class ResourceType {
diff --git a/guest/platform/rutabaga/RutabagaVirtGpuBlob.cpp b/guest/platform/rutabaga/RutabagaVirtGpuBlob.cpp
index 6f97ffb..d9392f0 100644
--- a/guest/platform/rutabaga/RutabagaVirtGpuBlob.cpp
+++ b/guest/platform/rutabaga/RutabagaVirtGpuBlob.cpp
@@ -71,6 +71,15 @@
return mEmulation->TransferFromHost(mContextId, mResourceId, offset, size);
}
+int RutabagaVirtGpuResource::transferFromHost(uint32_t x, uint32_t y, uint32_t w, uint32_t h) {
+ if (mResourceType != ResourceType::kPipe) {
+ ALOGE("Unexpected transferFromHost() called on non-pipe resource.");
+ return -1;
+ }
+
+ return mEmulation->TransferFromHost(mContextId, mResourceId, x, y, w, h);
+}
+
int RutabagaVirtGpuResource::transferToHost(uint32_t offset, uint32_t size) {
if (mResourceType != ResourceType::kPipe) {
ALOGE("Unexpected transferToHost() called on non-pipe resource.");
@@ -80,4 +89,13 @@
return mEmulation->TransferToHost(mContextId, mResourceId, offset, size);
}
+int RutabagaVirtGpuResource::transferToHost(uint32_t x, uint32_t y, uint32_t w, uint32_t h) {
+ if (mResourceType != ResourceType::kPipe) {
+ ALOGE("Unexpected transferToHost() called on non-pipe resource.");
+ return -1;
+ }
+
+ return mEmulation->TransferToHost(mContextId, mResourceId, x, y, w, h);
+}
+
} // namespace gfxstream
diff --git a/guest/platform/stub/StubVirtGpu.h b/guest/platform/stub/StubVirtGpu.h
index 7466cb5..6a00a4a 100644
--- a/guest/platform/stub/StubVirtGpu.h
+++ b/guest/platform/stub/StubVirtGpu.h
@@ -30,10 +30,10 @@
VirtGpuBlobMappingPtr createMapping(void) override;
int exportBlob(struct VirtGpuExternalHandle& handle) override;
- int transferFromHost(uint32_t offset, uint32_t size) override;
- int transferToHost(uint32_t offset, uint32_t size) override;
+ int transferFromHost(uint32_t x, uint32_t y, uint32_t w, uint32_t h) override;
+ int transferToHost(uint32_t x, uint32_t y, uint32_t w, uint32_t h) override;
- private:
+ private:
// Not owned. Really should use a ScopedFD for this, but doesn't matter since we have a
// singleton deviceimplemenentation anyways.
int64_t mDeviceHandle;
diff --git a/guest/platform/stub/StubVirtGpuBlob.cpp b/guest/platform/stub/StubVirtGpuBlob.cpp
index 4e8c23c..fb4c789 100644
--- a/guest/platform/stub/StubVirtGpuBlob.cpp
+++ b/guest/platform/stub/StubVirtGpuBlob.cpp
@@ -37,10 +37,6 @@
return -1;
}
-int StubVirtGpuBlob::transferFromHost(uint32_t, uint32_t) {
- return -1;
-}
+int StubVirtGpuBlob::transferFromHost(uint32_t, uint32_t, uint32_t, uint32_t) { return -1; }
-int StubVirtGpuBlob::transferToHost(uint32_t, uint32_t) {
- return -1;
-}
+int StubVirtGpuBlob::transferToHost(uint32_t, uint32_t, uint32_t, uint32_t) { return -1; }
diff --git a/host/features/Android.bp b/host/features/Android.bp
index 8326658..7ebc24a 100644
--- a/host/features/Android.bp
+++ b/host/features/Android.bp
@@ -1,4 +1,3 @@
-
package {
// See: http://go/android-license-faq
default_applicable_licenses: ["hardware_google_gfxstream_license"],