blob: dec2ad0b0e51a37850603c251509d8d48bbeec23 [file] [log] [blame]
// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef egl_Image_hpp
#define egl_Image_hpp
#include "libEGL/Texture.hpp"
#include "Renderer/Surface.hpp"
#include <GLES3/gl3.h>
#include <GLES2/gl2ext.h>
#if defined(__ANDROID__) && !defined(ANDROID_NDK_BUILD)
#include <system/window.h>
#include "../../Common/GrallocAndroid.hpp"
#endif
#if defined(__ANDROID__) && !defined(ANDROID_HOST_BUILD) && !defined(ANDROID_NDK_BUILD)
#include "../../Common/DebugAndroid.hpp"
#define LOGLOCK(fmt, ...) // TRACE(fmt " tid=%d", ##__VA_ARGS__, gettid())
#else
#include <assert.h>
#define LOGLOCK(...)
#endif
// Implementation-defined formats
#define SW_YV12_BT601 0x32315659 // YCrCb 4:2:0 Planar, 16-byte aligned, BT.601 color space, studio swing
#define SW_YV12_BT709 0x48315659 // YCrCb 4:2:0 Planar, 16-byte aligned, BT.709 color space, studio swing
#define SW_YV12_JFIF 0x4A315659 // YCrCb 4:2:0 Planar, 16-byte aligned, BT.601 color space, full swing
namespace gl
{
struct PixelStorageModes
{
GLint rowLength = 0;
GLint skipRows = 0;
GLint skipPixels = 0;
GLint alignment = 4;
GLint imageHeight = 0;
GLint skipImages = 0;
};
GLint GetSizedInternalFormat(GLint internalFormat, GLenum type);
sw::Format SelectInternalFormat(GLint format);
bool IsUnsizedInternalFormat(GLint internalformat);
GLenum GetBaseInternalFormat(GLint internalformat);
GLsizei ComputePitch(GLsizei width, GLenum format, GLenum type, GLint alignment);
GLsizei ComputeCompressedSize(GLsizei width, GLsizei height, GLenum format);
GLsizei ComputePixelSize(GLenum format, GLenum type);
size_t ComputePackingOffset(GLenum format, GLenum type, GLsizei width, GLsizei height, const PixelStorageModes &storageModes);
}
namespace egl
{
class ClientBuffer
{
public:
ClientBuffer(int width, int height, sw::Format format, void* buffer, size_t plane)
: width(width), height(height), format(format), buffer(buffer), plane(plane)
{}
int getWidth() const;
int getHeight() const;
sw::Format getFormat() const;
size_t getPlane() const;
int pitchP() const;
void retain();
void release();
void* lock(int x, int y, int z);
void unlock();
bool requiresSync() const;
private:
int width;
int height;
sw::Format format;
void* buffer;
size_t plane;
};
class [[clang::lto_visibility_public]] Image : public sw::Surface, public gl::Object
{
protected:
// 2D texture image
Image(Texture *parentTexture, GLsizei width, GLsizei height, GLint internalformat)
: sw::Surface(parentTexture->getResource(), width, height, 1, 0, 1, gl::SelectInternalFormat(internalformat), true, true),
width(width), height(height), depth(1), internalformat(internalformat), parentTexture(parentTexture)
{
shared = false;
Object::addRef();
parentTexture->addRef();
}
// 3D/Cube texture image
Image(Texture *parentTexture, GLsizei width, GLsizei height, GLsizei depth, int border, GLint internalformat)
: sw::Surface(parentTexture->getResource(), width, height, depth, border, 1, gl::SelectInternalFormat(internalformat), true, true),
width(width), height(height), depth(depth), internalformat(internalformat), parentTexture(parentTexture)
{
shared = false;
Object::addRef();
parentTexture->addRef();
}
// Native EGL image
Image(GLsizei width, GLsizei height, GLint internalformat, int pitchP)
: sw::Surface(nullptr, width, height, 1, 0, 1, gl::SelectInternalFormat(internalformat), true, true, pitchP),
width(width), height(height), depth(1), internalformat(internalformat), parentTexture(nullptr)
{
shared = true;
Object::addRef();
}
// Render target
Image(GLsizei width, GLsizei height, GLint internalformat, int multiSampleDepth, bool lockable)
: sw::Surface(nullptr, width, height, 1, 0, multiSampleDepth, gl::SelectInternalFormat(internalformat), lockable, true),
width(width), height(height), depth(1), internalformat(internalformat), parentTexture(nullptr)
{
shared = false;
Object::addRef();
}
public:
// 2D texture image
static Image *create(Texture *parentTexture, GLsizei width, GLsizei height, GLint internalformat);
// 3D/Cube texture image
static Image *create(Texture *parentTexture, GLsizei width, GLsizei height, GLsizei depth, int border, GLint internalformat);
// Native EGL image
static Image *create(GLsizei width, GLsizei height, GLint internalformat, int pitchP);
// Render target
static Image *create(GLsizei width, GLsizei height, GLint internalformat, int multiSampleDepth, bool lockable);
// Back buffer from client buffer
static Image *create(const egl::ClientBuffer& clientBuffer);
static size_t size(int width, int height, int depth, int border, int samples, GLint internalformat);
GLsizei getWidth() const
{
return width;
}
GLsizei getHeight() const
{
return height;
}
int getDepth() const
{
// FIXME: add member if the depth dimension (for 3D textures or 2D testure arrays)
// and multi sample depth are ever simultaneously required.
return depth;
}
GLint getFormat() const
{
return internalformat;
}
bool isShared() const
{
return shared;
}
void markShared()
{
shared = true;
}
virtual void *lock(int x, int y, int z, sw::Lock lock)
{
return lockExternal(x, y, z, lock, sw::PUBLIC);
}
unsigned int getPitch() const
{
return getExternalPitchB();
}
unsigned int getSlice() const
{
return getExternalSliceB();
}
virtual void unlock()
{
unlockExternal();
}
void *lockInternal(int x, int y, int z, sw::Lock lock, sw::Accessor client) override = 0;
void unlockInternal() override = 0;
void loadImageData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels);
void loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels);
void release() override = 0;
void unbind(const Texture *parent); // Break parent ownership and release
bool isChildOf(const Texture *parent) const;
virtual void destroyShared() // Release a shared image
{
assert(shared);
shared = false;
release();
}
protected:
const GLsizei width;
const GLsizei height;
const int depth;
const GLint internalformat;
bool shared; // Used as an EGLImage
egl::Texture *parentTexture;
~Image() override = 0;
void loadImageData(GLsizei width, GLsizei height, GLsizei depth, int inputPitch, int inputHeight, GLenum format, GLenum type, const void *input, void *buffer);
void loadStencilData(GLsizei width, GLsizei height, GLsizei depth, int inputPitch, int inputHeight, GLenum format, GLenum type, const void *input, void *buffer);
};
#if defined(__ANDROID__) && !defined(ANDROID_NDK_BUILD)
inline GLenum GLPixelFormatFromAndroid(int halFormat)
{
switch(halFormat)
{
case HAL_PIXEL_FORMAT_RGBA_8888: return GL_RGBA8;
#if ANDROID_PLATFORM_SDK_VERSION > 16
case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED: return GL_RGB8;
#endif
case HAL_PIXEL_FORMAT_RGBX_8888: return GL_RGB8;
case HAL_PIXEL_FORMAT_BGRA_8888: return GL_BGRA8_EXT;
case HAL_PIXEL_FORMAT_RGB_565: return GL_RGB565;
case HAL_PIXEL_FORMAT_YV12: return SW_YV12_BT601;
#ifdef GRALLOC_MODULE_API_VERSION_0_2
case HAL_PIXEL_FORMAT_YCbCr_420_888: return SW_YV12_BT601;
#endif
#if ANDROID_PLATFORM_SDK_VERSION >= 26
case HAL_PIXEL_FORMAT_RGBA_FP16: return GL_RGBA16F;
#endif
case HAL_PIXEL_FORMAT_RGB_888: // Unsupported.
default:
ERR("Unsupported EGL image format %d", halFormat); ASSERT(false);
return GL_NONE;
}
}
class AndroidNativeImage : public egl::Image
{
public:
explicit AndroidNativeImage(ANativeWindowBuffer *nativeBuffer)
: egl::Image(nativeBuffer->width, nativeBuffer->height,
GLPixelFormatFromAndroid(nativeBuffer->format),
nativeBuffer->stride),
nativeBuffer(nativeBuffer)
{
nativeBuffer->common.incRef(&nativeBuffer->common);
}
private:
ANativeWindowBuffer *nativeBuffer;
~AndroidNativeImage() override
{
sync(); // Wait for any threads that use this image to finish.
nativeBuffer->common.decRef(&nativeBuffer->common);
}
void *lockInternal(int x, int y, int z, sw::Lock lock, sw::Accessor client) override
{
LOGLOCK("image=%p op=%s.swsurface lock=%d", this, __FUNCTION__, lock);
// Always do this for reference counting.
void *data = sw::Surface::lockInternal(x, y, z, lock, client);
if(nativeBuffer)
{
if(x != 0 || y != 0 || z != 0)
{
TRACE("badness: %s called with unsupported parms: image=%p x=%d y=%d z=%d", __FUNCTION__, this, x, y, z);
}
LOGLOCK("image=%p op=%s.ani lock=%d", this, __FUNCTION__, lock);
// Lock the ANativeWindowBuffer and use its address.
data = lockNativeBuffer(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
}
return data;
}
void unlockInternal() override
{
if(nativeBuffer) // Unlock the buffer from ANativeWindowBuffer
{
LOGLOCK("image=%p op=%s.ani", this, __FUNCTION__);
unlockNativeBuffer();
}
LOGLOCK("image=%p op=%s.swsurface", this, __FUNCTION__);
sw::Surface::unlockInternal();
}
void *lock(int x, int y, int z, sw::Lock lock) override
{
LOGLOCK("image=%p op=%s lock=%d", this, __FUNCTION__, lock);
(void)sw::Surface::lockExternal(x, y, z, lock, sw::PUBLIC);
return lockNativeBuffer(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
}
void unlock() override
{
LOGLOCK("image=%p op=%s.ani", this, __FUNCTION__);
unlockNativeBuffer();
LOGLOCK("image=%p op=%s.swsurface", this, __FUNCTION__);
sw::Surface::unlockExternal();
}
void *lockNativeBuffer(int usage)
{
void *buffer = nullptr;
GrallocModule::getInstance()->lock(nativeBuffer->handle, usage, 0, 0, nativeBuffer->width, nativeBuffer->height, &buffer);
return buffer;
}
void unlockNativeBuffer()
{
GrallocModule::getInstance()->unlock(nativeBuffer->handle);
}
void release() override
{
Image::release();
}
};
#endif // __ANDROID__ && !defined(ANDROID_NDK_BUILD)
}
#endif // egl_Image_hpp