1/**************************************************************************
2 *
3 * Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com>
4 * Copyright 2010-2011 LunarG, Inc.
5 * All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sub license, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial portions
17 * of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
22 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 * DEALINGS IN THE SOFTWARE.
26 *
27 **************************************************************************/
28
29
30#include <assert.h>
31#include <string.h>
32
33#include "eglcurrent.h"
34#include "eglimage.h"
35#include "egllog.h"
36
37static EGLint
38_eglParseKHRImageAttribs(_EGLImageAttribs *attrs, _EGLDisplay *disp,
39                         EGLint attr, EGLint val)
40{
41   switch (attr) {
42   case EGL_IMAGE_PRESERVED_KHR:
43      if (!disp->Extensions.KHR_image_base)
44         return EGL_BAD_PARAMETER;
45
46      attrs->ImagePreserved = val;
47      break;
48
49   case EGL_GL_TEXTURE_LEVEL_KHR:
50      if (!disp->Extensions.KHR_gl_texture_2D_image)
51         return EGL_BAD_PARAMETER;
52
53      attrs->GLTextureLevel = val;
54      break;
55   case EGL_GL_TEXTURE_ZOFFSET_KHR:
56      if (!disp->Extensions.KHR_gl_texture_3D_image)
57         return EGL_BAD_PARAMETER;
58
59      attrs->GLTextureZOffset = val;
60      break;
61   default:
62      return EGL_BAD_PARAMETER;
63   }
64
65   return EGL_SUCCESS;
66}
67
68static EGLint
69_eglParseMESADrmImageAttribs(_EGLImageAttribs *attrs, _EGLDisplay *disp,
70                             EGLint attr, EGLint val)
71{
72   if (!disp->Extensions.MESA_drm_image)
73      return EGL_BAD_PARAMETER;
74
75   switch (attr) {
76   case EGL_WIDTH:
77      attrs->Width = val;
78      break;
79   case EGL_HEIGHT:
80      attrs->Height = val;
81      break;
82   case EGL_DRM_BUFFER_FORMAT_MESA:
83      attrs->DRMBufferFormatMESA = val;
84      break;
85   case EGL_DRM_BUFFER_USE_MESA:
86      attrs->DRMBufferUseMESA = val;
87      break;
88   case EGL_DRM_BUFFER_STRIDE_MESA:
89      attrs->DRMBufferStrideMESA = val;
90      break;
91   default:
92      return EGL_BAD_PARAMETER;
93   }
94
95   return EGL_SUCCESS;
96}
97
98static EGLint
99_eglParseWLBindWaylandDisplayAttribs(_EGLImageAttribs *attrs, _EGLDisplay *disp,
100                                     EGLint attr, EGLint val)
101{
102   if (!disp->Extensions.WL_bind_wayland_display)
103      return EGL_BAD_PARAMETER;
104
105   switch (attr) {
106   case EGL_WAYLAND_PLANE_WL:
107      attrs->PlaneWL = val;
108      break;
109   default:
110      return EGL_BAD_PARAMETER;
111   }
112
113   return EGL_SUCCESS;
114}
115
116static EGLint
117_eglParseEXTImageDmaBufImportAttribs(_EGLImageAttribs *attrs, _EGLDisplay *disp,
118                                     EGLint attr, EGLint val)
119{
120   if (!disp->Extensions.EXT_image_dma_buf_import)
121      return EGL_BAD_PARAMETER;
122
123   switch (attr) {
124   case EGL_WIDTH:
125      attrs->Width = val;
126      break;
127   case EGL_HEIGHT:
128      attrs->Height = val;
129      break;
130   case EGL_LINUX_DRM_FOURCC_EXT:
131      attrs->DMABufFourCC.Value = val;
132      attrs->DMABufFourCC.IsPresent = EGL_TRUE;
133      break;
134   case EGL_DMA_BUF_PLANE0_FD_EXT:
135      attrs->DMABufPlaneFds[0].Value = val;
136      attrs->DMABufPlaneFds[0].IsPresent = EGL_TRUE;
137      break;
138   case EGL_DMA_BUF_PLANE0_OFFSET_EXT:
139      attrs->DMABufPlaneOffsets[0].Value = val;
140      attrs->DMABufPlaneOffsets[0].IsPresent = EGL_TRUE;
141      break;
142   case EGL_DMA_BUF_PLANE0_PITCH_EXT:
143      attrs->DMABufPlanePitches[0].Value = val;
144      attrs->DMABufPlanePitches[0].IsPresent = EGL_TRUE;
145      break;
146   case EGL_DMA_BUF_PLANE1_FD_EXT:
147      attrs->DMABufPlaneFds[1].Value = val;
148      attrs->DMABufPlaneFds[1].IsPresent = EGL_TRUE;
149      break;
150   case EGL_DMA_BUF_PLANE1_OFFSET_EXT:
151      attrs->DMABufPlaneOffsets[1].Value = val;
152      attrs->DMABufPlaneOffsets[1].IsPresent = EGL_TRUE;
153      break;
154   case EGL_DMA_BUF_PLANE1_PITCH_EXT:
155      attrs->DMABufPlanePitches[1].Value = val;
156      attrs->DMABufPlanePitches[1].IsPresent = EGL_TRUE;
157      break;
158   case EGL_DMA_BUF_PLANE2_FD_EXT:
159      attrs->DMABufPlaneFds[2].Value = val;
160      attrs->DMABufPlaneFds[2].IsPresent = EGL_TRUE;
161      break;
162   case EGL_DMA_BUF_PLANE2_OFFSET_EXT:
163      attrs->DMABufPlaneOffsets[2].Value = val;
164      attrs->DMABufPlaneOffsets[2].IsPresent = EGL_TRUE;
165      break;
166   case EGL_DMA_BUF_PLANE2_PITCH_EXT:
167      attrs->DMABufPlanePitches[2].Value = val;
168      attrs->DMABufPlanePitches[2].IsPresent = EGL_TRUE;
169      break;
170   case EGL_YUV_COLOR_SPACE_HINT_EXT:
171      if (val != EGL_ITU_REC601_EXT && val != EGL_ITU_REC709_EXT &&
172          val != EGL_ITU_REC2020_EXT)
173         return EGL_BAD_ATTRIBUTE;
174
175      attrs->DMABufYuvColorSpaceHint.Value = val;
176      attrs->DMABufYuvColorSpaceHint.IsPresent = EGL_TRUE;
177      break;
178   case EGL_SAMPLE_RANGE_HINT_EXT:
179      if (val != EGL_YUV_FULL_RANGE_EXT && val != EGL_YUV_NARROW_RANGE_EXT)
180         return EGL_BAD_ATTRIBUTE;
181
182      attrs->DMABufSampleRangeHint.Value = val;
183      attrs->DMABufSampleRangeHint.IsPresent = EGL_TRUE;
184      break;
185   case EGL_YUV_CHROMA_HORIZONTAL_SITING_HINT_EXT:
186      if (val != EGL_YUV_CHROMA_SITING_0_EXT &&
187          val != EGL_YUV_CHROMA_SITING_0_5_EXT)
188         return EGL_BAD_ATTRIBUTE;
189
190      attrs->DMABufChromaHorizontalSiting.Value = val;
191      attrs->DMABufChromaHorizontalSiting.IsPresent = EGL_TRUE;
192      break;
193   case EGL_YUV_CHROMA_VERTICAL_SITING_HINT_EXT:
194      if (val != EGL_YUV_CHROMA_SITING_0_EXT &&
195          val != EGL_YUV_CHROMA_SITING_0_5_EXT)
196         return EGL_BAD_ATTRIBUTE;
197
198      attrs->DMABufChromaVerticalSiting.Value = val;
199      attrs->DMABufChromaVerticalSiting.IsPresent = EGL_TRUE;
200      break;
201   default:
202      return EGL_BAD_PARAMETER;
203   }
204
205   return EGL_SUCCESS;
206}
207
208static EGLint
209_eglParseEXTImageDmaBufImportModifiersAttribs(_EGLImageAttribs *attrs,
210                                              _EGLDisplay *disp,
211                                              EGLint attr, EGLint val)
212{
213   if (!disp->Extensions.EXT_image_dma_buf_import_modifiers)
214      return EGL_BAD_PARAMETER;
215
216   switch (attr) {
217   case EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT:
218      attrs->DMABufPlaneModifiersLo[0].Value = val;
219      attrs->DMABufPlaneModifiersLo[0].IsPresent = EGL_TRUE;
220      break;
221   case EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT:
222      attrs->DMABufPlaneModifiersHi[0].Value = val;
223      attrs->DMABufPlaneModifiersHi[0].IsPresent = EGL_TRUE;
224      break;
225   case EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT:
226      attrs->DMABufPlaneModifiersLo[1].Value = val;
227      attrs->DMABufPlaneModifiersLo[1].IsPresent = EGL_TRUE;
228      break;
229   case EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT:
230      attrs->DMABufPlaneModifiersHi[1].Value = val;
231      attrs->DMABufPlaneModifiersHi[1].IsPresent = EGL_TRUE;
232      break;
233   case EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT:
234      attrs->DMABufPlaneModifiersLo[2].Value = val;
235      attrs->DMABufPlaneModifiersLo[2].IsPresent = EGL_TRUE;
236      break;
237   case EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT:
238      attrs->DMABufPlaneModifiersHi[2].Value = val;
239      attrs->DMABufPlaneModifiersHi[2].IsPresent = EGL_TRUE;
240      break;
241   case EGL_DMA_BUF_PLANE3_FD_EXT:
242      attrs->DMABufPlaneFds[3].Value = val;
243      attrs->DMABufPlaneFds[3].IsPresent = EGL_TRUE;
244      break;
245   case EGL_DMA_BUF_PLANE3_OFFSET_EXT:
246      attrs->DMABufPlaneOffsets[3].Value = val;
247      attrs->DMABufPlaneOffsets[3].IsPresent = EGL_TRUE;
248      break;
249   case EGL_DMA_BUF_PLANE3_PITCH_EXT:
250      attrs->DMABufPlanePitches[3].Value = val;
251      attrs->DMABufPlanePitches[3].IsPresent = EGL_TRUE;
252      break;
253   case EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT:
254      attrs->DMABufPlaneModifiersLo[3].Value = val;
255      attrs->DMABufPlaneModifiersLo[3].IsPresent = EGL_TRUE;
256      break;
257   case EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT:
258      attrs->DMABufPlaneModifiersHi[3].Value = val;
259      attrs->DMABufPlaneModifiersHi[3].IsPresent = EGL_TRUE;
260      break;
261   default:
262      return EGL_BAD_PARAMETER;
263   }
264
265   return EGL_SUCCESS;
266}
267
268/**
269 * Parse the list of image attributes.
270 *
271 * Returns EGL_TRUE on success and EGL_FALSE otherwise.
272 * Function calls _eglError to set the correct error code.
273 */
274EGLBoolean
275_eglParseImageAttribList(_EGLImageAttribs *attrs, _EGLDisplay *disp,
276                         const EGLint *attrib_list)
277{
278   EGLint i, err;
279
280   memset(attrs, 0, sizeof(*attrs));
281
282   if (!attrib_list)
283      return EGL_TRUE;
284
285   for (i = 0; attrib_list[i] != EGL_NONE; i++) {
286      EGLint attr = attrib_list[i++];
287      EGLint val = attrib_list[i];
288
289      err = _eglParseKHRImageAttribs(attrs, disp, attr, val);
290      if (err == EGL_SUCCESS)
291         continue;
292
293      err = _eglParseMESADrmImageAttribs(attrs, disp, attr, val);
294      if (err == EGL_SUCCESS)
295         continue;
296
297      err = _eglParseWLBindWaylandDisplayAttribs(attrs, disp, attr, val);
298      if (err == EGL_SUCCESS)
299         continue;
300
301      err = _eglParseEXTImageDmaBufImportAttribs(attrs, disp, attr, val);
302      if (err == EGL_SUCCESS)
303         continue;
304
305      /* EXT_image_dma_buf_import states that if invalid value is provided for
306       * its attributes, we should return EGL_BAD_ATTRIBUTE.
307       * Bail out ASAP, since follow-up calls can return another EGL_BAD error.
308       */
309      if (err == EGL_BAD_ATTRIBUTE)
310         return _eglError(err, __func__);
311
312      err = _eglParseEXTImageDmaBufImportModifiersAttribs(attrs, disp, attr, val);
313      if (err == EGL_SUCCESS)
314         continue;
315
316      return _eglError(err, __func__);
317   }
318
319   return EGL_TRUE;
320}
321