1// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#ifndef egl_Image_hpp
16#define egl_Image_hpp
17
18#include "libEGL/Texture.hpp"
19#include "Renderer/Surface.hpp"
20
21#include <GLES3/gl3.h>
22#include <GLES2/gl2ext.h>
23
24#if defined(__ANDROID__) && !defined(ANDROID_NDK_BUILD)
25#include <system/window.h>
26#include "../../Common/GrallocAndroid.hpp"
27#endif
28
29#if defined(__ANDROID__) && !defined(ANDROID_HOST_BUILD) && !defined(ANDROID_NDK_BUILD)
30#include "../../Common/DebugAndroid.hpp"
31#define LOGLOCK(fmt, ...) // TRACE(fmt " tid=%d", ##__VA_ARGS__, gettid())
32#else
33#include <assert.h>
34#define LOGLOCK(...)
35#endif
36
37// Implementation-defined formats
38#define SW_YV12_BT601 0x32315659 // YCrCb 4:2:0 Planar, 16-byte aligned, BT.601 color space, studio swing
39#define SW_YV12_BT709 0x48315659 // YCrCb 4:2:0 Planar, 16-byte aligned, BT.709 color space, studio swing
40#define SW_YV12_JFIF 0x4A315659 // YCrCb 4:2:0 Planar, 16-byte aligned, BT.601 color space, full swing
41
42namespace gl
43{
44
45struct PixelStorageModes
46{
47 GLint rowLength = 0;
48 GLint skipRows = 0;
49 GLint skipPixels = 0;
50 GLint alignment = 4;
51 GLint imageHeight = 0;
52 GLint skipImages = 0;
53};
54
55GLint GetSizedInternalFormat(GLint internalFormat, GLenum type);
56sw::Format SelectInternalFormat(GLint format);
57bool IsUnsizedInternalFormat(GLint internalformat);
58GLenum GetBaseInternalFormat(GLint internalformat);
59GLsizei ComputePitch(GLsizei width, GLenum format, GLenum type, GLint alignment);
60GLsizei ComputeCompressedSize(GLsizei width, GLsizei height, GLenum format);
61GLsizei ComputePixelSize(GLenum format, GLenum type);
62size_t ComputePackingOffset(GLenum format, GLenum type, GLsizei width, GLsizei height, const PixelStorageModes &storageModes);
63
64}
65
66namespace egl
67{
68
69class ClientBuffer
70{
71public:
72 ClientBuffer(int width, int height, sw::Format format, void* buffer, size_t plane)
73 : width(width), height(height), format(format), buffer(buffer), plane(plane)
74 {}
75
76 int getWidth() const;
77 int getHeight() const;
78 sw::Format getFormat() const;
79 size_t getPlane() const;
80 int pitchP() const;
81 void retain();
82 void release();
83 void* lock(int x, int y, int z);
84 void unlock();
85 bool requiresSync() const;
86
87private:
88 int width;
89 int height;
90 sw::Format format;
91 void* buffer;
92 size_t plane;
93};
94
95class [[clang::lto_visibility_public]] Image : public sw::Surface, public gl::Object
96{
97protected:
98 // 2D texture image
99 Image(Texture *parentTexture, GLsizei width, GLsizei height, GLint internalformat)
100 : sw::Surface(parentTexture->getResource(), width, height, 1, 0, 1, gl::SelectInternalFormat(internalformat), true, true),
101 width(width), height(height), depth(1), internalformat(internalformat), parentTexture(parentTexture)
102 {
103 shared = false;
104 Object::addRef();
105 parentTexture->addRef();
106 }
107
108 // 3D/Cube texture image
109 Image(Texture *parentTexture, GLsizei width, GLsizei height, GLsizei depth, int border, GLint internalformat)
110 : sw::Surface(parentTexture->getResource(), width, height, depth, border, 1, gl::SelectInternalFormat(internalformat), true, true),
111 width(width), height(height), depth(depth), internalformat(internalformat), parentTexture(parentTexture)
112 {
113 shared = false;
114 Object::addRef();
115 parentTexture->addRef();
116 }
117
118 // Native EGL image
119 Image(GLsizei width, GLsizei height, GLint internalformat, int pitchP)
120 : sw::Surface(nullptr, width, height, 1, 0, 1, gl::SelectInternalFormat(internalformat), true, true, pitchP),
121 width(width), height(height), depth(1), internalformat(internalformat), parentTexture(nullptr)
122 {
123 shared = true;
124 Object::addRef();
125 }
126
127 // Render target
128 Image(GLsizei width, GLsizei height, GLint internalformat, int multiSampleDepth, bool lockable)
129 : sw::Surface(nullptr, width, height, 1, 0, multiSampleDepth, gl::SelectInternalFormat(internalformat), lockable, true),
130 width(width), height(height), depth(1), internalformat(internalformat), parentTexture(nullptr)
131 {
132 shared = false;
133 Object::addRef();
134 }
135
136public:
137 // 2D texture image
138 static Image *create(Texture *parentTexture, GLsizei width, GLsizei height, GLint internalformat);
139
140 // 3D/Cube texture image
141 static Image *create(Texture *parentTexture, GLsizei width, GLsizei height, GLsizei depth, int border, GLint internalformat);
142
143 // Native EGL image
144 static Image *create(GLsizei width, GLsizei height, GLint internalformat, int pitchP);
145
146 // Render target
147 static Image *create(GLsizei width, GLsizei height, GLint internalformat, int multiSampleDepth, bool lockable);
148
149 // Back buffer from client buffer
150 static Image *create(const egl::ClientBuffer& clientBuffer);
151
152 static size_t size(int width, int height, int depth, int border, int samples, GLint internalformat);
153
154 GLsizei getWidth() const
155 {
156 return width;
157 }
158
159 GLsizei getHeight() const
160 {
161 return height;
162 }
163
164 int getDepth() const
165 {
166 // FIXME: add member if the depth dimension (for 3D textures or 2D testure arrays)
167 // and multi sample depth are ever simultaneously required.
168 return depth;
169 }
170
171 GLint getFormat() const
172 {
173 return internalformat;
174 }
175
176 bool isShared() const
177 {
178 return shared;
179 }
180
181 void markShared()
182 {
183 shared = true;
184 }
185
186 virtual void *lock(int x, int y, int z, sw::Lock lock)
187 {
188 return lockExternal(x, y, z, lock, sw::PUBLIC);
189 }
190
191 unsigned int getPitch() const
192 {
193 return getExternalPitchB();
194 }
195
196 unsigned int getSlice() const
197 {
198 return getExternalSliceB();
199 }
200
201 virtual void unlock()
202 {
203 unlockExternal();
204 }
205
206 void *lockInternal(int x, int y, int z, sw::Lock lock, sw::Accessor client) override = 0;
207 void unlockInternal() override = 0;
208
209 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);
210 void loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels);
211
212 void release() override = 0;
213 void unbind(const Texture *parent); // Break parent ownership and release
214 bool isChildOf(const Texture *parent) const;
215
216 virtual void destroyShared() // Release a shared image
217 {
218 assert(shared);
219 shared = false;
220 release();
221 }
222
223protected:
224 const GLsizei width;
225 const GLsizei height;
226 const int depth;
227 const GLint internalformat;
228
229 bool shared; // Used as an EGLImage
230
231 egl::Texture *parentTexture;
232
233 ~Image() override = 0;
234
235 void loadImageData(GLsizei width, GLsizei height, GLsizei depth, int inputPitch, int inputHeight, GLenum format, GLenum type, const void *input, void *buffer);
236 void loadStencilData(GLsizei width, GLsizei height, GLsizei depth, int inputPitch, int inputHeight, GLenum format, GLenum type, const void *input, void *buffer);
237};
238
239#if defined(__ANDROID__) && !defined(ANDROID_NDK_BUILD)
240
241inline GLenum GLPixelFormatFromAndroid(int halFormat)
242{
243 switch(halFormat)
244 {
245 case HAL_PIXEL_FORMAT_RGBA_8888: return GL_RGBA8;
246#if ANDROID_PLATFORM_SDK_VERSION > 16
247 case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED: return GL_RGB8;
248#endif
249 case HAL_PIXEL_FORMAT_RGBX_8888: return GL_RGB8;
250 case HAL_PIXEL_FORMAT_BGRA_8888: return GL_BGRA8_EXT;
251 case HAL_PIXEL_FORMAT_RGB_565: return GL_RGB565;
252 case HAL_PIXEL_FORMAT_YV12: return SW_YV12_BT601;
253#ifdef GRALLOC_MODULE_API_VERSION_0_2
254 case HAL_PIXEL_FORMAT_YCbCr_420_888: return SW_YV12_BT601;
255#endif
256#if ANDROID_PLATFORM_SDK_VERSION >= 26
257 case HAL_PIXEL_FORMAT_RGBA_FP16: return GL_RGBA16F;
258#endif
259 case HAL_PIXEL_FORMAT_RGB_888: // Unsupported.
260 default:
261 ERR("Unsupported EGL image format %d", halFormat); ASSERT(false);
262 return GL_NONE;
263 }
264}
265
266class AndroidNativeImage : public egl::Image
267{
268public:
269 explicit AndroidNativeImage(ANativeWindowBuffer *nativeBuffer)
270 : egl::Image(nativeBuffer->width, nativeBuffer->height,
271 GLPixelFormatFromAndroid(nativeBuffer->format),
272 nativeBuffer->stride),
273 nativeBuffer(nativeBuffer)
274 {
275 nativeBuffer->common.incRef(&nativeBuffer->common);
276 }
277
278private:
279 ANativeWindowBuffer *nativeBuffer;
280
281 ~AndroidNativeImage() override
282 {
283 sync(); // Wait for any threads that use this image to finish.
284
285 nativeBuffer->common.decRef(&nativeBuffer->common);
286 }
287
288 void *lockInternal(int x, int y, int z, sw::Lock lock, sw::Accessor client) override
289 {
290 LOGLOCK("image=%p op=%s.swsurface lock=%d", this, __FUNCTION__, lock);
291
292 // Always do this for reference counting.
293 void *data = sw::Surface::lockInternal(x, y, z, lock, client);
294
295 if(nativeBuffer)
296 {
297 if(x != 0 || y != 0 || z != 0)
298 {
299 TRACE("badness: %s called with unsupported parms: image=%p x=%d y=%d z=%d", __FUNCTION__, this, x, y, z);
300 }
301
302 LOGLOCK("image=%p op=%s.ani lock=%d", this, __FUNCTION__, lock);
303
304 // Lock the ANativeWindowBuffer and use its address.
305 data = lockNativeBuffer(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
306
307 if(lock == sw::LOCK_UNLOCKED)
308 {
309 // We're never going to get a corresponding unlock, so unlock
310 // immediately. This keeps the gralloc reference counts sane.
311 unlockNativeBuffer();
312 }
313 }
314
315 return data;
316 }
317
318 void unlockInternal() override
319 {
320 if(nativeBuffer) // Unlock the buffer from ANativeWindowBuffer
321 {
322 LOGLOCK("image=%p op=%s.ani", this, __FUNCTION__);
323 unlockNativeBuffer();
324 }
325
326 LOGLOCK("image=%p op=%s.swsurface", this, __FUNCTION__);
327 sw::Surface::unlockInternal();
328 }
329
330 void *lock(int x, int y, int z, sw::Lock lock) override
331 {
332 LOGLOCK("image=%p op=%s lock=%d", this, __FUNCTION__, lock);
333 (void)sw::Surface::lockExternal(x, y, z, lock, sw::PUBLIC);
334
335 return lockNativeBuffer(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
336 }
337
338 void unlock() override
339 {
340 LOGLOCK("image=%p op=%s.ani", this, __FUNCTION__);
341 unlockNativeBuffer();
342
343 LOGLOCK("image=%p op=%s.swsurface", this, __FUNCTION__);
344 sw::Surface::unlockExternal();
345 }
346
347 void *lockNativeBuffer(int usage)
348 {
349 void *buffer = nullptr;
350 GrallocModule::getInstance()->lock(nativeBuffer->handle, usage, 0, 0, nativeBuffer->width, nativeBuffer->height, &buffer);
351
352 return buffer;
353 }
354
355 void unlockNativeBuffer()
356 {
357 GrallocModule::getInstance()->unlock(nativeBuffer->handle);
358 }
359
360 void release() override
361 {
362 Image::release();
363 }
364};
365
366#endif // __ANDROID__ && !defined(ANDROID_NDK_BUILD)
367
368}
369
370#endif // egl_Image_hpp
371