Implement EGLImage external texture API for GL.
Tests are based on the IOSurfaceWrappingTests. Sampling tests are not implemented, since they would require support for the samplerExternalOES sampler type in WGSL. Bug: chromium:1205155 Change-Id: Icc114eaf6efaee93f1b8486e615f0fd307f23080 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/50201 Commit-Queue: Stephen White <senorblanco@chromium.org> Reviewed-by: Corentin Wallez <cwallez@google.com> Reviewed-by: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
parent
b3c371031c
commit
b5652c75d2
|
@ -37,6 +37,7 @@ using GLhalf = unsigned short;
|
||||||
using GLint64 = khronos_int64_t;
|
using GLint64 = khronos_int64_t;
|
||||||
using GLuint64 = khronos_uint64_t;
|
using GLuint64 = khronos_uint64_t;
|
||||||
using GLsync = struct __GLsync*;
|
using GLsync = struct __GLsync*;
|
||||||
|
using GLeglImageOES = void*;
|
||||||
using GLDEBUGPROC = void(KHRONOS_APIENTRY*)(GLenum source,
|
using GLDEBUGPROC = void(KHRONOS_APIENTRY*)(GLenum source,
|
||||||
GLenum type,
|
GLenum type,
|
||||||
GLuint id,
|
GLuint id,
|
||||||
|
|
|
@ -176,6 +176,65 @@ namespace dawn_native { namespace opengl {
|
||||||
mFencesInFlight.emplace(sync, GetLastSubmittedCommandSerial());
|
mFencesInFlight.emplace(sync, GetLastSubmittedCommandSerial());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MaybeError Device::ValidateEGLImageCanBeWrapped(const TextureDescriptor* descriptor,
|
||||||
|
::EGLImage image) {
|
||||||
|
if (descriptor->dimension != wgpu::TextureDimension::e2D) {
|
||||||
|
return DAWN_VALIDATION_ERROR("EGLImage texture must be 2D");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (descriptor->usage & (wgpu::TextureUsage::Sampled | wgpu::TextureUsage::Storage)) {
|
||||||
|
return DAWN_VALIDATION_ERROR("EGLImage texture cannot have sampled or storage usage");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (descriptor->mipLevelCount != 1) {
|
||||||
|
return DAWN_VALIDATION_ERROR("EGLImage mip level count must be 1");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (descriptor->size.depthOrArrayLayers != 1) {
|
||||||
|
return DAWN_VALIDATION_ERROR("EGLImage array layer count must be 1");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (descriptor->sampleCount != 1) {
|
||||||
|
return DAWN_VALIDATION_ERROR("EGLImage sample count must be 1");
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
TextureBase* Device::CreateTextureWrappingEGLImage(const ExternalImageDescriptor* descriptor,
|
||||||
|
::EGLImage image) {
|
||||||
|
const TextureDescriptor* textureDescriptor =
|
||||||
|
reinterpret_cast<const TextureDescriptor*>(descriptor->cTextureDescriptor);
|
||||||
|
|
||||||
|
if (ConsumedError(ValidateTextureDescriptor(this, textureDescriptor))) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
if (ConsumedError(ValidateEGLImageCanBeWrapped(textureDescriptor, image))) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint tex;
|
||||||
|
gl.GenTextures(1, &tex);
|
||||||
|
gl.BindTexture(GL_TEXTURE_2D, tex);
|
||||||
|
gl.EGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
|
||||||
|
|
||||||
|
GLint width, height, internalFormat;
|
||||||
|
gl.GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
|
||||||
|
gl.GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height);
|
||||||
|
gl.GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &internalFormat);
|
||||||
|
|
||||||
|
if (textureDescriptor->size.width != static_cast<uint32_t>(width) ||
|
||||||
|
textureDescriptor->size.height != static_cast<uint32_t>(height) ||
|
||||||
|
textureDescriptor->size.depthOrArrayLayers != 1) {
|
||||||
|
ConsumedError(DAWN_VALIDATION_ERROR("EGLImage size doesn't match descriptor"));
|
||||||
|
gl.DeleteTextures(1, &tex);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(dawn:803): Validate the OpenGL texture format from the EGLImage against the format
|
||||||
|
// in the passed-in TextureDescriptor.
|
||||||
|
return new Texture(this, textureDescriptor, tex, TextureBase::TextureState::OwnedInternal);
|
||||||
|
}
|
||||||
|
|
||||||
MaybeError Device::TickImpl() {
|
MaybeError Device::TickImpl() {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,8 @@
|
||||||
# include "common/windows_with_undefs.h"
|
# include "common/windows_with_undefs.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
typedef void* EGLImage;
|
||||||
|
|
||||||
namespace dawn_native { namespace opengl {
|
namespace dawn_native { namespace opengl {
|
||||||
|
|
||||||
class Device : public DeviceBase {
|
class Device : public DeviceBase {
|
||||||
|
@ -49,6 +51,11 @@ namespace dawn_native { namespace opengl {
|
||||||
|
|
||||||
void SubmitFenceSync();
|
void SubmitFenceSync();
|
||||||
|
|
||||||
|
MaybeError ValidateEGLImageCanBeWrapped(const TextureDescriptor* descriptor,
|
||||||
|
::EGLImage image);
|
||||||
|
TextureBase* CreateTextureWrappingEGLImage(const ExternalImageDescriptor* descriptor,
|
||||||
|
::EGLImage image);
|
||||||
|
|
||||||
ResultOrError<Ref<CommandBufferBase>> CreateCommandBuffer(
|
ResultOrError<Ref<CommandBufferBase>> CreateCommandBuffer(
|
||||||
CommandEncoder* encoder,
|
CommandEncoder* encoder,
|
||||||
const CommandBufferDescriptor* descriptor) override;
|
const CommandBufferDescriptor* descriptor) override;
|
||||||
|
|
|
@ -50,4 +50,15 @@ namespace dawn_native { namespace opengl {
|
||||||
return static_cast<WGPUTextureFormat>(impl->GetPreferredFormat());
|
return static_cast<WGPUTextureFormat>(impl->GetPreferredFormat());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExternalImageDescriptorEGLImage::ExternalImageDescriptorEGLImage()
|
||||||
|
: ExternalImageDescriptor(ExternalImageType::EGLImage) {
|
||||||
|
}
|
||||||
|
|
||||||
|
WGPUTexture WrapExternalEGLImage(WGPUDevice cDevice,
|
||||||
|
const ExternalImageDescriptorEGLImage* descriptor) {
|
||||||
|
Device* device = reinterpret_cast<Device*>(cDevice);
|
||||||
|
TextureBase* texture = device->CreateTextureWrappingEGLImage(descriptor, descriptor->image);
|
||||||
|
return reinterpret_cast<WGPUTexture>(texture);
|
||||||
|
}
|
||||||
|
|
||||||
}} // namespace dawn_native::opengl
|
}} // namespace dawn_native::opengl
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
"supported_extensions": [
|
"supported_extensions": [
|
||||||
"GL_EXT_texture_compression_s3tc",
|
"GL_EXT_texture_compression_s3tc",
|
||||||
"GL_EXT_texture_compression_s3tc_srgb"
|
"GL_EXT_texture_compression_s3tc_srgb",
|
||||||
|
"GL_OES_EGL_image"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -215,6 +215,7 @@ namespace dawn_native {
|
||||||
DmaBuf,
|
DmaBuf,
|
||||||
IOSurface,
|
IOSurface,
|
||||||
DXGISharedHandle,
|
DXGISharedHandle,
|
||||||
|
EGLImage,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Common properties of external images
|
// Common properties of external images
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
#ifndef DAWNNATIVE_OPENGLBACKEND_H_
|
#ifndef DAWNNATIVE_OPENGLBACKEND_H_
|
||||||
#define DAWNNATIVE_OPENGLBACKEND_H_
|
#define DAWNNATIVE_OPENGLBACKEND_H_
|
||||||
|
|
||||||
|
typedef void* EGLImage;
|
||||||
|
|
||||||
#include <dawn/dawn_wsi.h>
|
#include <dawn/dawn_wsi.h>
|
||||||
#include <dawn_native/DawnNative.h>
|
#include <dawn_native/DawnNative.h>
|
||||||
|
|
||||||
|
@ -38,6 +40,16 @@ namespace dawn_native { namespace opengl {
|
||||||
DAWN_NATIVE_EXPORT WGPUTextureFormat
|
DAWN_NATIVE_EXPORT WGPUTextureFormat
|
||||||
GetNativeSwapChainPreferredFormat(const DawnSwapChainImplementation* swapChain);
|
GetNativeSwapChainPreferredFormat(const DawnSwapChainImplementation* swapChain);
|
||||||
|
|
||||||
|
struct DAWN_NATIVE_EXPORT ExternalImageDescriptorEGLImage : ExternalImageDescriptor {
|
||||||
|
public:
|
||||||
|
ExternalImageDescriptorEGLImage();
|
||||||
|
|
||||||
|
::EGLImage image;
|
||||||
|
};
|
||||||
|
|
||||||
|
DAWN_NATIVE_EXPORT WGPUTexture
|
||||||
|
WrapExternalEGLImage(WGPUDevice device, const ExternalImageDescriptorEGLImage* descriptor);
|
||||||
|
|
||||||
}} // namespace dawn_native::opengl
|
}} // namespace dawn_native::opengl
|
||||||
|
|
||||||
#endif // DAWNNATIVE_OPENGLBACKEND_H_
|
#endif // DAWNNATIVE_OPENGLBACKEND_H_
|
||||||
|
|
|
@ -449,6 +449,11 @@ source_set("dawn_white_box_tests_sources") {
|
||||||
deps += [ "${dawn_root}/src/utils:dawn_glfw" ]
|
deps += [ "${dawn_root}/src/utils:dawn_glfw" ]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dawn_enable_opengles) {
|
||||||
|
sources += [ "white_box/EGLImageWrappingTests.cpp" ]
|
||||||
|
deps += [ "//third_party/angle:libEGL" ]
|
||||||
|
}
|
||||||
|
|
||||||
libs = []
|
libs = []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,356 @@
|
||||||
|
// Copyright 2021 The Dawn Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "tests/DawnTest.h"
|
||||||
|
|
||||||
|
#include "common/DynamicLib.h"
|
||||||
|
#include "dawn_native/OpenGLBackend.h"
|
||||||
|
#include "dawn_native/opengl/DeviceGL.h"
|
||||||
|
#include "utils/ComboRenderPipelineDescriptor.h"
|
||||||
|
#include "utils/WGPUHelpers.h"
|
||||||
|
|
||||||
|
#include <EGL/egl.h>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class EGLFunctions {
|
||||||
|
public:
|
||||||
|
EGLFunctions() {
|
||||||
|
#ifdef DAWN_PLATFORM_WINDOWS
|
||||||
|
const char* eglLib = "libEGL.dll";
|
||||||
|
#else
|
||||||
|
const char* eglLib = "libEGL.so";
|
||||||
|
#endif
|
||||||
|
EXPECT_TRUE(mlibEGL.Open(eglLib));
|
||||||
|
CreateImage = reinterpret_cast<PFNEGLCREATEIMAGEPROC>(LoadProc("eglCreateImage"));
|
||||||
|
DestroyImage = reinterpret_cast<PFNEGLDESTROYIMAGEPROC>(LoadProc("eglDestroyImage"));
|
||||||
|
GetCurrentContext =
|
||||||
|
reinterpret_cast<PFNEGLGETCURRENTCONTEXTPROC>(LoadProc("eglGetCurrentContext"));
|
||||||
|
GetCurrentDisplay =
|
||||||
|
reinterpret_cast<PFNEGLGETCURRENTDISPLAYPROC>(LoadProc("eglGetCurrentDisplay"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void* LoadProc(const char* name) {
|
||||||
|
void* proc = mlibEGL.GetProc(name);
|
||||||
|
EXPECT_NE(proc, nullptr);
|
||||||
|
return proc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
PFNEGLCREATEIMAGEPROC CreateImage;
|
||||||
|
PFNEGLDESTROYIMAGEPROC DestroyImage;
|
||||||
|
PFNEGLGETCURRENTCONTEXTPROC GetCurrentContext;
|
||||||
|
PFNEGLGETCURRENTDISPLAYPROC GetCurrentDisplay;
|
||||||
|
|
||||||
|
private:
|
||||||
|
DynamicLib mlibEGL;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ScopedEGLImage {
|
||||||
|
public:
|
||||||
|
ScopedEGLImage(PFNEGLDESTROYIMAGEPROC destroyImage,
|
||||||
|
PFNGLDELETETEXTURESPROC deleteTextures,
|
||||||
|
EGLDisplay display,
|
||||||
|
EGLImage image,
|
||||||
|
GLuint texture)
|
||||||
|
: mDestroyImage(destroyImage),
|
||||||
|
mDeleteTextures(deleteTextures),
|
||||||
|
mDisplay(display),
|
||||||
|
mImage(image),
|
||||||
|
mTexture(texture) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ScopedEGLImage(ScopedEGLImage&& other) {
|
||||||
|
if (mImage != nullptr) {
|
||||||
|
mDestroyImage(mDisplay, mImage);
|
||||||
|
}
|
||||||
|
if (mTexture != 0) {
|
||||||
|
mDeleteTextures(1, &mTexture);
|
||||||
|
}
|
||||||
|
mDestroyImage = std::move(other.mDestroyImage);
|
||||||
|
mDeleteTextures = std::move(other.mDeleteTextures);
|
||||||
|
mDisplay = std::move(other.mDisplay);
|
||||||
|
mImage = std::move(other.mImage);
|
||||||
|
mTexture = std::move(other.mTexture);
|
||||||
|
}
|
||||||
|
|
||||||
|
~ScopedEGLImage() {
|
||||||
|
if (mTexture != 0) {
|
||||||
|
mDeleteTextures(1, &mTexture);
|
||||||
|
}
|
||||||
|
if (mImage != nullptr) {
|
||||||
|
mDestroyImage(mDisplay, mImage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EGLImage getImage() const {
|
||||||
|
return mImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint getTexture() const {
|
||||||
|
return mTexture;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
PFNEGLDESTROYIMAGEPROC mDestroyImage = nullptr;
|
||||||
|
PFNGLDELETETEXTURESPROC mDeleteTextures = nullptr;
|
||||||
|
EGLDisplay mDisplay = nullptr;
|
||||||
|
EGLImage mImage = nullptr;
|
||||||
|
GLuint mTexture = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
|
class EGLImageTestBase : public DawnTest {
|
||||||
|
public:
|
||||||
|
ScopedEGLImage CreateEGLImage(uint32_t width,
|
||||||
|
uint32_t height,
|
||||||
|
GLenum internalFormat,
|
||||||
|
GLenum format,
|
||||||
|
GLenum type,
|
||||||
|
void* data,
|
||||||
|
size_t size) {
|
||||||
|
dawn_native::opengl::Device* openglDevice =
|
||||||
|
reinterpret_cast<dawn_native::opengl::Device*>(device.Get());
|
||||||
|
const dawn_native::opengl::OpenGLFunctions& gl = openglDevice->gl;
|
||||||
|
GLuint tex;
|
||||||
|
gl.GenTextures(1, &tex);
|
||||||
|
gl.BindTexture(GL_TEXTURE_2D, tex);
|
||||||
|
gl.TexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, type, data);
|
||||||
|
EGLAttrib attribs[1] = {EGL_NONE};
|
||||||
|
EGLClientBuffer buffer = reinterpret_cast<EGLClientBuffer>(tex);
|
||||||
|
EGLDisplay dpy = egl.GetCurrentDisplay();
|
||||||
|
EGLContext ctx = egl.GetCurrentContext();
|
||||||
|
EGLImage eglImage = egl.CreateImage(dpy, ctx, EGL_GL_TEXTURE_2D, buffer, attribs);
|
||||||
|
EXPECT_NE(nullptr, eglImage);
|
||||||
|
|
||||||
|
return ScopedEGLImage(egl.DestroyImage, gl.DeleteTextures, dpy, eglImage, tex);
|
||||||
|
}
|
||||||
|
wgpu::Texture WrapEGLImage(const wgpu::TextureDescriptor* descriptor, EGLImage eglImage) {
|
||||||
|
dawn_native::opengl::ExternalImageDescriptorEGLImage externDesc;
|
||||||
|
externDesc.cTextureDescriptor = reinterpret_cast<const WGPUTextureDescriptor*>(descriptor);
|
||||||
|
externDesc.image = eglImage;
|
||||||
|
WGPUTexture texture = dawn_native::opengl::WrapExternalEGLImage(device.Get(), &externDesc);
|
||||||
|
return wgpu::Texture::Acquire(texture);
|
||||||
|
}
|
||||||
|
EGLFunctions egl;
|
||||||
|
};
|
||||||
|
|
||||||
|
// A small fixture used to initialize default data for the EGLImage validation tests.
|
||||||
|
// These tests are skipped if the harness is using the wire.
|
||||||
|
class EGLImageValidationTests : public EGLImageTestBase {
|
||||||
|
public:
|
||||||
|
EGLImageValidationTests() {
|
||||||
|
descriptor.dimension = wgpu::TextureDimension::e2D;
|
||||||
|
descriptor.format = wgpu::TextureFormat::RGBA8Unorm;
|
||||||
|
descriptor.size = {10, 10, 1};
|
||||||
|
descriptor.sampleCount = 1;
|
||||||
|
descriptor.mipLevelCount = 1;
|
||||||
|
descriptor.usage = wgpu::TextureUsage::RenderAttachment;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScopedEGLImage CreateDefaultEGLImage() {
|
||||||
|
return CreateEGLImage(10, 10, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, nullptr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
wgpu::TextureDescriptor descriptor;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Test a successful wrapping of an EGLImage in a texture
|
||||||
|
TEST_P(EGLImageValidationTests, Success) {
|
||||||
|
DAWN_TEST_UNSUPPORTED_IF(UsesWire());
|
||||||
|
ScopedEGLImage image = CreateDefaultEGLImage();
|
||||||
|
wgpu::Texture texture = WrapEGLImage(&descriptor, image.getImage());
|
||||||
|
ASSERT_NE(texture.Get(), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test an error occurs if the texture descriptor is invalid
|
||||||
|
TEST_P(EGLImageValidationTests, InvalidTextureDescriptor) {
|
||||||
|
DAWN_TEST_UNSUPPORTED_IF(UsesWire());
|
||||||
|
|
||||||
|
wgpu::ChainedStruct chainedDescriptor;
|
||||||
|
descriptor.nextInChain = &chainedDescriptor;
|
||||||
|
|
||||||
|
ScopedEGLImage image = CreateDefaultEGLImage();
|
||||||
|
ASSERT_DEVICE_ERROR(wgpu::Texture texture = WrapEGLImage(&descriptor, image.getImage()));
|
||||||
|
ASSERT_EQ(texture.Get(), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test an error occurs if the descriptor dimension isn't 2D
|
||||||
|
TEST_P(EGLImageValidationTests, InvalidTextureDimension) {
|
||||||
|
DAWN_TEST_UNSUPPORTED_IF(UsesWire());
|
||||||
|
descriptor.dimension = wgpu::TextureDimension::e3D;
|
||||||
|
|
||||||
|
ScopedEGLImage image = CreateDefaultEGLImage();
|
||||||
|
ASSERT_DEVICE_ERROR(wgpu::Texture texture = WrapEGLImage(&descriptor, image.getImage()));
|
||||||
|
|
||||||
|
ASSERT_EQ(texture.Get(), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test an error occurs if the texture usage is not RenderAttachment
|
||||||
|
TEST_P(EGLImageValidationTests, InvalidTextureUsage) {
|
||||||
|
DAWN_TEST_UNSUPPORTED_IF(UsesWire());
|
||||||
|
descriptor.usage = wgpu::TextureUsage::Sampled;
|
||||||
|
|
||||||
|
ScopedEGLImage image = CreateDefaultEGLImage();
|
||||||
|
wgpu::Texture texture;
|
||||||
|
ASSERT_DEVICE_ERROR(texture = WrapEGLImage(&descriptor, image.getImage()));
|
||||||
|
|
||||||
|
ASSERT_EQ(texture.Get(), nullptr);
|
||||||
|
descriptor.usage = wgpu::TextureUsage::Storage;
|
||||||
|
|
||||||
|
ASSERT_DEVICE_ERROR(texture = WrapEGLImage(&descriptor, image.getImage()));
|
||||||
|
|
||||||
|
ASSERT_EQ(texture.Get(), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test an error occurs if the descriptor mip level count isn't 1
|
||||||
|
TEST_P(EGLImageValidationTests, InvalidMipLevelCount) {
|
||||||
|
DAWN_TEST_UNSUPPORTED_IF(UsesWire());
|
||||||
|
descriptor.mipLevelCount = 2;
|
||||||
|
|
||||||
|
ScopedEGLImage image = CreateDefaultEGLImage();
|
||||||
|
ASSERT_DEVICE_ERROR(wgpu::Texture texture = WrapEGLImage(&descriptor, image.getImage()));
|
||||||
|
ASSERT_EQ(texture.Get(), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test an error occurs if the descriptor depth isn't 1
|
||||||
|
TEST_P(EGLImageValidationTests, InvalidDepth) {
|
||||||
|
DAWN_TEST_UNSUPPORTED_IF(UsesWire());
|
||||||
|
descriptor.size.depthOrArrayLayers = 2;
|
||||||
|
|
||||||
|
ScopedEGLImage image = CreateDefaultEGLImage();
|
||||||
|
ASSERT_DEVICE_ERROR(wgpu::Texture texture = WrapEGLImage(&descriptor, image.getImage()));
|
||||||
|
ASSERT_EQ(texture.Get(), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test an error occurs if the descriptor sample count isn't 1
|
||||||
|
TEST_P(EGLImageValidationTests, InvalidSampleCount) {
|
||||||
|
DAWN_TEST_UNSUPPORTED_IF(UsesWire());
|
||||||
|
descriptor.sampleCount = 4;
|
||||||
|
|
||||||
|
ScopedEGLImage image = CreateDefaultEGLImage();
|
||||||
|
ASSERT_DEVICE_ERROR(wgpu::Texture texture = WrapEGLImage(&descriptor, image.getImage()));
|
||||||
|
ASSERT_EQ(texture.Get(), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test an error occurs if the descriptor width doesn't match the surface's
|
||||||
|
TEST_P(EGLImageValidationTests, InvalidWidth) {
|
||||||
|
DAWN_TEST_UNSUPPORTED_IF(UsesWire());
|
||||||
|
descriptor.size.width = 11;
|
||||||
|
|
||||||
|
ScopedEGLImage image = CreateDefaultEGLImage();
|
||||||
|
ASSERT_DEVICE_ERROR(wgpu::Texture texture = WrapEGLImage(&descriptor, image.getImage()));
|
||||||
|
ASSERT_EQ(texture.Get(), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test an error occurs if the descriptor height doesn't match the surface's
|
||||||
|
TEST_P(EGLImageValidationTests, InvalidHeight) {
|
||||||
|
DAWN_TEST_UNSUPPORTED_IF(UsesWire());
|
||||||
|
descriptor.size.height = 11;
|
||||||
|
|
||||||
|
ScopedEGLImage image = CreateDefaultEGLImage();
|
||||||
|
ASSERT_DEVICE_ERROR(wgpu::Texture texture = WrapEGLImage(&descriptor, image.getImage()));
|
||||||
|
ASSERT_EQ(texture.Get(), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fixture to test using EGLImages through different usages.
|
||||||
|
// These tests are skipped if the harness is using the wire.
|
||||||
|
class EGLImageUsageTests : public EGLImageTestBase {
|
||||||
|
public:
|
||||||
|
// Test that clearing using BeginRenderPass writes correct data in the eglImage.
|
||||||
|
void DoClearTest(EGLImage eglImage,
|
||||||
|
GLuint texture,
|
||||||
|
wgpu::TextureFormat format,
|
||||||
|
GLenum glFormat,
|
||||||
|
GLenum glType,
|
||||||
|
void* data,
|
||||||
|
size_t dataSize) {
|
||||||
|
dawn_native::opengl::Device* openglDevice =
|
||||||
|
reinterpret_cast<dawn_native::opengl::Device*>(device.Get());
|
||||||
|
const dawn_native::opengl::OpenGLFunctions& gl = openglDevice->gl;
|
||||||
|
|
||||||
|
// Get a texture view for the eglImage
|
||||||
|
wgpu::TextureDescriptor textureDescriptor;
|
||||||
|
textureDescriptor.dimension = wgpu::TextureDimension::e2D;
|
||||||
|
textureDescriptor.format = format;
|
||||||
|
textureDescriptor.size = {1, 1, 1};
|
||||||
|
textureDescriptor.sampleCount = 1;
|
||||||
|
textureDescriptor.mipLevelCount = 1;
|
||||||
|
textureDescriptor.usage = wgpu::TextureUsage::RenderAttachment;
|
||||||
|
wgpu::Texture eglImageTexture = WrapEGLImage(&textureDescriptor, eglImage);
|
||||||
|
ASSERT_NE(eglImageTexture, nullptr);
|
||||||
|
|
||||||
|
wgpu::TextureView eglImageView = eglImageTexture.CreateView();
|
||||||
|
|
||||||
|
utils::ComboRenderPassDescriptor renderPassDescriptor({eglImageView}, {});
|
||||||
|
renderPassDescriptor.cColorAttachments[0].clearColor = {1 / 255.0f, 2 / 255.0f, 3 / 255.0f,
|
||||||
|
4 / 255.0f};
|
||||||
|
|
||||||
|
// Execute commands to clear the eglImage
|
||||||
|
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||||
|
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPassDescriptor);
|
||||||
|
pass.EndPass();
|
||||||
|
|
||||||
|
wgpu::CommandBuffer commands = encoder.Finish();
|
||||||
|
queue.Submit(1, &commands);
|
||||||
|
|
||||||
|
// Check the correct data was written
|
||||||
|
std::vector<uint8_t> result(dataSize);
|
||||||
|
GLuint fbo;
|
||||||
|
gl.GenFramebuffers(1, &fbo);
|
||||||
|
gl.BindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||||
|
gl.FramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture,
|
||||||
|
0);
|
||||||
|
gl.ReadPixels(0, 0, 1, 1, glFormat, glType, result.data());
|
||||||
|
gl.BindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
gl.DeleteFramebuffers(1, &fbo);
|
||||||
|
ASSERT_EQ(0, memcmp(result.data(), data, dataSize));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Test clearing a R8 EGLImage
|
||||||
|
TEST_P(EGLImageUsageTests, ClearR8EGLImage) {
|
||||||
|
DAWN_TEST_UNSUPPORTED_IF(UsesWire());
|
||||||
|
ScopedEGLImage eglImage = CreateEGLImage(1, 1, GL_R8, GL_RED, GL_UNSIGNED_BYTE, nullptr, 0);
|
||||||
|
|
||||||
|
uint8_t data = 0x01;
|
||||||
|
DoClearTest(eglImage.getImage(), eglImage.getTexture(), wgpu::TextureFormat::R8Unorm, GL_RED,
|
||||||
|
GL_UNSIGNED_BYTE, &data, sizeof(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test clearing a RG8 EGLImage
|
||||||
|
TEST_P(EGLImageUsageTests, ClearRG8EGLImage) {
|
||||||
|
DAWN_TEST_UNSUPPORTED_IF(UsesWire());
|
||||||
|
ScopedEGLImage eglImage = CreateEGLImage(1, 1, GL_RG8, GL_RG, GL_UNSIGNED_BYTE, nullptr, 0);
|
||||||
|
|
||||||
|
uint16_t data = 0x0201;
|
||||||
|
DoClearTest(eglImage.getImage(), eglImage.getTexture(), wgpu::TextureFormat::RG8Unorm, GL_RG,
|
||||||
|
GL_UNSIGNED_BYTE, &data, sizeof(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test clearing an RGBA8 EGLImage
|
||||||
|
TEST_P(EGLImageUsageTests, ClearRGBA8EGLImage) {
|
||||||
|
DAWN_TEST_UNSUPPORTED_IF(UsesWire());
|
||||||
|
ScopedEGLImage eglImage = CreateEGLImage(1, 1, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, nullptr, 0);
|
||||||
|
|
||||||
|
uint32_t data = 0x04030201;
|
||||||
|
DoClearTest(eglImage.getImage(), eglImage.getTexture(), wgpu::TextureFormat::RGBA8Unorm,
|
||||||
|
GL_RGBA, GL_UNSIGNED_BYTE, &data, sizeof(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
DAWN_INSTANTIATE_TEST(EGLImageValidationTests, OpenGLESBackend());
|
||||||
|
DAWN_INSTANTIATE_TEST(EGLImageUsageTests, OpenGLESBackend());
|
Loading…
Reference in New Issue