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 | |
42 | namespace gl |
43 | { |
44 | |
45 | struct 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 | |
55 | GLint GetSizedInternalFormat(GLint internalFormat, GLenum type); |
56 | sw::Format SelectInternalFormat(GLint format); |
57 | bool IsUnsizedInternalFormat(GLint internalformat); |
58 | GLenum GetBaseInternalFormat(GLint internalformat); |
59 | GLsizei ComputePitch(GLsizei width, GLenum format, GLenum type, GLint alignment); |
60 | GLsizei ComputeCompressedSize(GLsizei width, GLsizei height, GLenum format); |
61 | GLsizei ComputePixelSize(GLenum format, GLenum type); |
62 | size_t ComputePackingOffset(GLenum format, GLenum type, GLsizei width, GLsizei height, const PixelStorageModes &storageModes); |
63 | |
64 | } |
65 | |
66 | namespace egl |
67 | { |
68 | |
69 | class ClientBuffer |
70 | { |
71 | public: |
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 | |
87 | private: |
88 | int width; |
89 | int height; |
90 | sw::Format format; |
91 | void* buffer; |
92 | size_t plane; |
93 | }; |
94 | |
95 | class [[clang::lto_visibility_public]] Image : public sw::Surface, public gl::Object |
96 | { |
97 | protected: |
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 | |
136 | public: |
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 | |
223 | protected: |
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 | |
241 | inline 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 | |
266 | class AndroidNativeImage : public egl::Image |
267 | { |
268 | public: |
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 | |
278 | private: |
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 | |