blob: 6c710031f1d3ca5f17c08ac2d75063d421087c03 [file] [log] [blame]
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001#include "precompiled.h"
2//
Geoff Langcec35902014-04-16 10:52:36 -04003// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved.
Geoff Lange8ebe7f2013-08-05 15:03:13 -04004// Use of this source code is governed by a BSD-style license that can be
5// found in the LICENSE file.
6//
7
8// validationES3.cpp: Validation functions for OpenGL ES 3.0 entry point parameters
9
10#include "libGLESv2/validationES3.h"
Geoff Langce635692013-09-24 13:56:32 -040011#include "libGLESv2/validationES.h"
Geoff Lange8ebe7f2013-08-05 15:03:13 -040012#include "libGLESv2/Context.h"
13#include "libGLESv2/Texture.h"
14#include "libGLESv2/Framebuffer.h"
15#include "libGLESv2/Renderbuffer.h"
16#include "libGLESv2/formatutils.h"
17#include "libGLESv2/main.h"
Jamie Madille261b442014-06-25 12:42:21 -040018#include "libGLESv2/FramebufferAttachment.h"
Geoff Lange8ebe7f2013-08-05 15:03:13 -040019
20#include "common/mathutil.h"
21
22namespace gl
23{
24
Geoff Lang5d601382014-07-22 15:14:06 -040025// ES3 has a specific set of permutations of internal formats, formats and types which are acceptable.
26struct ES3FormatCombination
27{
28 GLenum internalFormat;
29 GLenum format;
30 GLenum type;
31};
32
33bool operator<(const ES3FormatCombination& a, const ES3FormatCombination& b)
34{
35 return memcmp(&a, &b, sizeof(ES3FormatCombination)) < 0;
36}
37
38typedef std::set<ES3FormatCombination> ES3FormatCombinationSet;
39
40static inline void InsertES3FormatCombo(ES3FormatCombinationSet *set, GLenum internalFormat, GLenum format, GLenum type)
41{
42 ES3FormatCombination info;
43 info.internalFormat = internalFormat;
44 info.format = format;
45 info.type = type;
46 set->insert(info);
47}
48
49ES3FormatCombinationSet BuildES3FormatSet()
50{
51 ES3FormatCombinationSet set;
52
53 // Format combinations from ES 3.0.1 spec, table 3.2
54
55 // | Internal format | Format | Type |
56 // | | | |
57 InsertES3FormatCombo(&set, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE );
58 InsertES3FormatCombo(&set, GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_BYTE );
59 InsertES3FormatCombo(&set, GL_RGBA4, GL_RGBA, GL_UNSIGNED_BYTE );
60 InsertES3FormatCombo(&set, GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE );
61 InsertES3FormatCombo(&set, GL_RGBA8_SNORM, GL_RGBA, GL_BYTE );
62 InsertES3FormatCombo(&set, GL_RGBA4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4 );
63 InsertES3FormatCombo(&set, GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV );
64 InsertES3FormatCombo(&set, GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV );
65 InsertES3FormatCombo(&set, GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1 );
66 InsertES3FormatCombo(&set, GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT );
67 InsertES3FormatCombo(&set, GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT_OES );
68 InsertES3FormatCombo(&set, GL_RGBA32F, GL_RGBA, GL_FLOAT );
69 InsertES3FormatCombo(&set, GL_RGBA16F, GL_RGBA, GL_FLOAT );
70 InsertES3FormatCombo(&set, GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE );
71 InsertES3FormatCombo(&set, GL_RGBA8I, GL_RGBA_INTEGER, GL_BYTE );
72 InsertES3FormatCombo(&set, GL_RGBA16UI, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT );
73 InsertES3FormatCombo(&set, GL_RGBA16I, GL_RGBA_INTEGER, GL_SHORT );
74 InsertES3FormatCombo(&set, GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT );
75 InsertES3FormatCombo(&set, GL_RGBA32I, GL_RGBA_INTEGER, GL_INT );
76 InsertES3FormatCombo(&set, GL_RGB10_A2UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT_2_10_10_10_REV );
77 InsertES3FormatCombo(&set, GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE );
78 InsertES3FormatCombo(&set, GL_RGB565, GL_RGB, GL_UNSIGNED_BYTE );
79 InsertES3FormatCombo(&set, GL_SRGB8, GL_RGB, GL_UNSIGNED_BYTE );
80 InsertES3FormatCombo(&set, GL_RGB8_SNORM, GL_RGB, GL_BYTE );
81 InsertES3FormatCombo(&set, GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5 );
82 InsertES3FormatCombo(&set, GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV );
83 InsertES3FormatCombo(&set, GL_RGB9_E5, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV );
84 InsertES3FormatCombo(&set, GL_RGB16F, GL_RGB, GL_HALF_FLOAT );
85 InsertES3FormatCombo(&set, GL_RGB16F, GL_RGB, GL_HALF_FLOAT_OES );
86 InsertES3FormatCombo(&set, GL_R11F_G11F_B10F, GL_RGB, GL_HALF_FLOAT );
87 InsertES3FormatCombo(&set, GL_R11F_G11F_B10F, GL_RGB, GL_HALF_FLOAT_OES );
88 InsertES3FormatCombo(&set, GL_RGB9_E5, GL_RGB, GL_HALF_FLOAT );
89 InsertES3FormatCombo(&set, GL_RGB9_E5, GL_RGB, GL_HALF_FLOAT_OES );
90 InsertES3FormatCombo(&set, GL_RGB32F, GL_RGB, GL_FLOAT );
91 InsertES3FormatCombo(&set, GL_RGB16F, GL_RGB, GL_FLOAT );
92 InsertES3FormatCombo(&set, GL_R11F_G11F_B10F, GL_RGB, GL_FLOAT );
93 InsertES3FormatCombo(&set, GL_RGB9_E5, GL_RGB, GL_FLOAT );
94 InsertES3FormatCombo(&set, GL_RGB8UI, GL_RGB_INTEGER, GL_UNSIGNED_BYTE );
95 InsertES3FormatCombo(&set, GL_RGB8I, GL_RGB_INTEGER, GL_BYTE );
96 InsertES3FormatCombo(&set, GL_RGB16UI, GL_RGB_INTEGER, GL_UNSIGNED_SHORT );
97 InsertES3FormatCombo(&set, GL_RGB16I, GL_RGB_INTEGER, GL_SHORT );
98 InsertES3FormatCombo(&set, GL_RGB32UI, GL_RGB_INTEGER, GL_UNSIGNED_INT );
99 InsertES3FormatCombo(&set, GL_RGB32I, GL_RGB_INTEGER, GL_INT );
100 InsertES3FormatCombo(&set, GL_RG8, GL_RG, GL_UNSIGNED_BYTE );
101 InsertES3FormatCombo(&set, GL_RG8_SNORM, GL_RG, GL_BYTE );
102 InsertES3FormatCombo(&set, GL_RG16F, GL_RG, GL_HALF_FLOAT );
103 InsertES3FormatCombo(&set, GL_RG16F, GL_RG, GL_HALF_FLOAT_OES );
104 InsertES3FormatCombo(&set, GL_RG32F, GL_RG, GL_FLOAT );
105 InsertES3FormatCombo(&set, GL_RG16F, GL_RG, GL_FLOAT );
106 InsertES3FormatCombo(&set, GL_RG8UI, GL_RG_INTEGER, GL_UNSIGNED_BYTE );
107 InsertES3FormatCombo(&set, GL_RG8I, GL_RG_INTEGER, GL_BYTE );
108 InsertES3FormatCombo(&set, GL_RG16UI, GL_RG_INTEGER, GL_UNSIGNED_SHORT );
109 InsertES3FormatCombo(&set, GL_RG16I, GL_RG_INTEGER, GL_SHORT );
110 InsertES3FormatCombo(&set, GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT );
111 InsertES3FormatCombo(&set, GL_RG32I, GL_RG_INTEGER, GL_INT );
112 InsertES3FormatCombo(&set, GL_R8, GL_RED, GL_UNSIGNED_BYTE );
113 InsertES3FormatCombo(&set, GL_R8_SNORM, GL_RED, GL_BYTE );
114 InsertES3FormatCombo(&set, GL_R16F, GL_RED, GL_HALF_FLOAT );
115 InsertES3FormatCombo(&set, GL_R16F, GL_RED, GL_HALF_FLOAT_OES );
116 InsertES3FormatCombo(&set, GL_R32F, GL_RED, GL_FLOAT );
117 InsertES3FormatCombo(&set, GL_R16F, GL_RED, GL_FLOAT );
118 InsertES3FormatCombo(&set, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE );
119 InsertES3FormatCombo(&set, GL_R8I, GL_RED_INTEGER, GL_BYTE );
120 InsertES3FormatCombo(&set, GL_R16UI, GL_RED_INTEGER, GL_UNSIGNED_SHORT );
121 InsertES3FormatCombo(&set, GL_R16I, GL_RED_INTEGER, GL_SHORT );
122 InsertES3FormatCombo(&set, GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT );
123 InsertES3FormatCombo(&set, GL_R32I, GL_RED_INTEGER, GL_INT );
124
125 // Unsized formats
126 InsertES3FormatCombo(&set, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE );
127 InsertES3FormatCombo(&set, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4 );
128 InsertES3FormatCombo(&set, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1 );
129 InsertES3FormatCombo(&set, GL_RGB, GL_RGB, GL_UNSIGNED_BYTE );
130 InsertES3FormatCombo(&set, GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5 );
131 InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE );
132 InsertES3FormatCombo(&set, GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE );
133 InsertES3FormatCombo(&set, GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE );
134 InsertES3FormatCombo(&set, GL_SRGB_ALPHA_EXT, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE );
135 InsertES3FormatCombo(&set, GL_SRGB_EXT, GL_SRGB_EXT, GL_UNSIGNED_BYTE );
136
137 // Depth stencil formats
138 InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT );
139 InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT );
140 InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT );
141 InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT );
142 InsertES3FormatCombo(&set, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8 );
143 InsertES3FormatCombo(&set, GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV);
144
145 // From GL_EXT_sRGB
146 InsertES3FormatCombo(&set, GL_SRGB8_ALPHA8_EXT, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE );
147 InsertES3FormatCombo(&set, GL_SRGB8, GL_SRGB_EXT, GL_UNSIGNED_BYTE );
148
149 // From GL_OES_texture_float
150 InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_FLOAT );
151 InsertES3FormatCombo(&set, GL_LUMINANCE, GL_LUMINANCE, GL_FLOAT );
152 InsertES3FormatCombo(&set, GL_ALPHA, GL_ALPHA, GL_FLOAT );
153
154 // From GL_OES_texture_half_float
155 InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT );
156 InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES );
157 InsertES3FormatCombo(&set, GL_LUMINANCE, GL_LUMINANCE, GL_HALF_FLOAT );
158 InsertES3FormatCombo(&set, GL_LUMINANCE, GL_LUMINANCE, GL_HALF_FLOAT_OES );
159 InsertES3FormatCombo(&set, GL_ALPHA, GL_ALPHA, GL_HALF_FLOAT );
160 InsertES3FormatCombo(&set, GL_ALPHA, GL_ALPHA, GL_HALF_FLOAT_OES );
161
162 // From GL_EXT_texture_format_BGRA8888
163 InsertES3FormatCombo(&set, GL_BGRA_EXT, GL_BGRA_EXT, GL_UNSIGNED_BYTE );
164
165 // From GL_EXT_texture_storage
166 // | Internal format | Format | Type |
167 // | | | |
168 InsertES3FormatCombo(&set, GL_ALPHA8_EXT, GL_ALPHA, GL_UNSIGNED_BYTE );
169 InsertES3FormatCombo(&set, GL_LUMINANCE8_EXT, GL_LUMINANCE, GL_UNSIGNED_BYTE );
170 InsertES3FormatCombo(&set, GL_LUMINANCE8_ALPHA8_EXT, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE );
171 InsertES3FormatCombo(&set, GL_ALPHA32F_EXT, GL_ALPHA, GL_FLOAT );
172 InsertES3FormatCombo(&set, GL_LUMINANCE32F_EXT, GL_LUMINANCE, GL_FLOAT );
173 InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA32F_EXT, GL_LUMINANCE_ALPHA, GL_FLOAT );
174 InsertES3FormatCombo(&set, GL_ALPHA16F_EXT, GL_ALPHA, GL_HALF_FLOAT );
175 InsertES3FormatCombo(&set, GL_ALPHA16F_EXT, GL_ALPHA, GL_HALF_FLOAT_OES );
176 InsertES3FormatCombo(&set, GL_LUMINANCE16F_EXT, GL_LUMINANCE, GL_HALF_FLOAT );
177 InsertES3FormatCombo(&set, GL_LUMINANCE16F_EXT, GL_LUMINANCE, GL_HALF_FLOAT_OES );
178 InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA16F_EXT, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT );
179 InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA16F_EXT, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES );
180
181 // From GL_EXT_texture_storage and GL_EXT_texture_format_BGRA8888
182 InsertES3FormatCombo(&set, GL_BGRA8_EXT, GL_BGRA_EXT, GL_UNSIGNED_BYTE );
183 InsertES3FormatCombo(&set, GL_BGRA4_ANGLEX, GL_BGRA_EXT, GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT);
184 InsertES3FormatCombo(&set, GL_BGRA4_ANGLEX, GL_BGRA_EXT, GL_UNSIGNED_BYTE );
185 InsertES3FormatCombo(&set, GL_BGR5_A1_ANGLEX, GL_BGRA_EXT, GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT);
186 InsertES3FormatCombo(&set, GL_BGR5_A1_ANGLEX, GL_BGRA_EXT, GL_UNSIGNED_BYTE );
187
188 // From GL_ANGLE_depth_texture
189 InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT32_OES, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT_24_8_OES );
190
191 // Compressed formats
192 // From ES 3.0.1 spec, table 3.16
193 // | Internal format | Format | Type |
194 // | | | |
195 InsertES3FormatCombo(&set, GL_COMPRESSED_R11_EAC, GL_COMPRESSED_R11_EAC, GL_UNSIGNED_BYTE);
196 InsertES3FormatCombo(&set, GL_COMPRESSED_R11_EAC, GL_COMPRESSED_R11_EAC, GL_UNSIGNED_BYTE);
197 InsertES3FormatCombo(&set, GL_COMPRESSED_SIGNED_R11_EAC, GL_COMPRESSED_SIGNED_R11_EAC, GL_UNSIGNED_BYTE);
198 InsertES3FormatCombo(&set, GL_COMPRESSED_RG11_EAC, GL_COMPRESSED_RG11_EAC, GL_UNSIGNED_BYTE);
199 InsertES3FormatCombo(&set, GL_COMPRESSED_SIGNED_RG11_EAC, GL_COMPRESSED_SIGNED_RG11_EAC, GL_UNSIGNED_BYTE);
200 InsertES3FormatCombo(&set, GL_COMPRESSED_RGB8_ETC2, GL_COMPRESSED_RGB8_ETC2, GL_UNSIGNED_BYTE);
201 InsertES3FormatCombo(&set, GL_COMPRESSED_SRGB8_ETC2, GL_COMPRESSED_SRGB8_ETC2, GL_UNSIGNED_BYTE);
202 InsertES3FormatCombo(&set, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE);
203 InsertES3FormatCombo(&set, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE);
204 InsertES3FormatCombo(&set, GL_COMPRESSED_RGBA8_ETC2_EAC, GL_COMPRESSED_RGBA8_ETC2_EAC, GL_UNSIGNED_BYTE);
205 InsertES3FormatCombo(&set, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, GL_UNSIGNED_BYTE);
206
207
208 // From GL_EXT_texture_compression_dxt1
209 InsertES3FormatCombo(&set, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE);
210 InsertES3FormatCombo(&set, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE);
211
212 // From GL_ANGLE_texture_compression_dxt3
213 InsertES3FormatCombo(&set, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, GL_UNSIGNED_BYTE);
214
215 // From GL_ANGLE_texture_compression_dxt5
216 InsertES3FormatCombo(&set, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, GL_UNSIGNED_BYTE);
217
218 return set;
219}
220
221static bool ValidateTexImageFormatCombination(gl::Context *context, GLenum internalFormat, GLenum format, GLenum type)
222{
223 // Note: dEQP 2013.4 expects an INVALID_VALUE error for TexImage3D with an invalid
224 // internal format. (dEQP-GLES3.functional.negative_api.texture.teximage3d)
225 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
226 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
227 {
228 return gl::error(GL_INVALID_ENUM, false);
229 }
230
231 // The type and format are valid if any supported internal format has that type and format
232 bool formatSupported = false;
233 bool typeSupported = false;
234
235 static const ES3FormatCombinationSet es3FormatSet = BuildES3FormatSet();
236 for (ES3FormatCombinationSet::const_iterator i = es3FormatSet.begin(); i != es3FormatSet.end(); i++)
237 {
238 if (i->format == format || i->type == type)
239 {
240 const gl::InternalFormat &info = gl::GetInternalFormatInfo(i->internalFormat);
241 bool supported = info.textureSupport(context->getClientVersion(), context->getExtensions());
242 if (supported && formatInfo.type == type)
243 {
244 typeSupported = true;
245 }
246 if (supported && formatInfo.format == format)
247 {
248 formatSupported = true;
249 }
250 }
251 }
252
253 if (!typeSupported || !formatSupported)
254 {
255 return gl::error(GL_INVALID_ENUM, false);
256 }
257
258 // Check if this is a valid format combination to load texture data
259 ES3FormatCombination searchFormat;
260 searchFormat.internalFormat = internalFormat;
261 searchFormat.format = format;
262 searchFormat.type = type;
263
264 if (es3FormatSet.find(searchFormat) == es3FormatSet.end())
265 {
266 return gl::error(GL_INVALID_OPERATION, false);
267 }
268
269 return true;
270}
271
Geoff Lang005df412013-10-16 14:12:50 -0400272bool ValidateES3TexImageParameters(gl::Context *context, GLenum target, GLint level, GLenum internalformat, bool isCompressed, bool isSubImage,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400273 GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Jamie Madillefb2a6f2013-09-24 10:22:42 -0400274 GLint border, GLenum format, GLenum type, const GLvoid *pixels)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400275{
Jamie Madill6f38f822014-06-06 17:12:20 -0400276 if (!ValidTexture2DDestinationTarget(context, target))
277 {
278 return gl::error(GL_INVALID_ENUM, false);
279 }
280
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400281 // Validate image size
Geoff Langce635692013-09-24 13:56:32 -0400282 if (!ValidImageSize(context, target, level, width, height, depth))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400283 {
284 return gl::error(GL_INVALID_VALUE, false);
285 }
286
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400287 // Verify zero border
288 if (border != 0)
289 {
290 return gl::error(GL_INVALID_VALUE, false);
291 }
292
Jamie Madill6f38f822014-06-06 17:12:20 -0400293 if (xoffset < 0 || yoffset < 0 || zoffset < 0 ||
294 std::numeric_limits<GLsizei>::max() - xoffset < width ||
295 std::numeric_limits<GLsizei>::max() - yoffset < height ||
296 std::numeric_limits<GLsizei>::max() - zoffset < depth)
297 {
298 return gl::error(GL_INVALID_VALUE, false);
299 }
300
Geoff Langaae65a42014-05-26 12:43:44 -0400301 const gl::Caps &caps = context->getCaps();
302
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400303 gl::Texture *texture = NULL;
304 bool textureCompressed = false;
305 GLenum textureInternalFormat = GL_NONE;
306 GLint textureLevelWidth = 0;
307 GLint textureLevelHeight = 0;
308 GLint textureLevelDepth = 0;
309 switch (target)
310 {
311 case GL_TEXTURE_2D:
312 {
Geoff Langaae65a42014-05-26 12:43:44 -0400313 if (static_cast<GLuint>(width) > (caps.max2DTextureSize >> level) ||
314 static_cast<GLuint>(height) > (caps.max2DTextureSize >> level))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400315 {
316 return gl::error(GL_INVALID_VALUE, false);
317 }
318
319 gl::Texture2D *texture2d = context->getTexture2D();
320 if (texture2d)
321 {
322 textureCompressed = texture2d->isCompressed(level);
323 textureInternalFormat = texture2d->getInternalFormat(level);
324 textureLevelWidth = texture2d->getWidth(level);
325 textureLevelHeight = texture2d->getHeight(level);
326 textureLevelDepth = 1;
327 texture = texture2d;
328 }
329 }
330 break;
331
332 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
333 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
334 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
335 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
336 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
337 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
338 {
339 if (!isSubImage && width != height)
340 {
341 return gl::error(GL_INVALID_VALUE, false);
342 }
343
Geoff Langaae65a42014-05-26 12:43:44 -0400344 if (static_cast<GLuint>(width) > (caps.maxCubeMapTextureSize >> level))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400345 {
346 return gl::error(GL_INVALID_VALUE, false);
347 }
348
349 gl::TextureCubeMap *textureCube = context->getTextureCubeMap();
350 if (textureCube)
351 {
352 textureCompressed = textureCube->isCompressed(target, level);
353 textureInternalFormat = textureCube->getInternalFormat(target, level);
354 textureLevelWidth = textureCube->getWidth(target, level);
355 textureLevelHeight = textureCube->getHeight(target, level);
356 textureLevelDepth = 1;
357 texture = textureCube;
358 }
359 }
360 break;
361
362 case GL_TEXTURE_3D:
363 {
Geoff Langaae65a42014-05-26 12:43:44 -0400364 if (static_cast<GLuint>(width) > (caps.max3DTextureSize >> level) ||
365 static_cast<GLuint>(height) > (caps.max3DTextureSize >> level) ||
366 static_cast<GLuint>(depth) > (caps.max3DTextureSize >> level))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400367 {
368 return gl::error(GL_INVALID_VALUE, false);
369 }
370
371 gl::Texture3D *texture3d = context->getTexture3D();
372 if (texture3d)
373 {
374 textureCompressed = texture3d->isCompressed(level);
375 textureInternalFormat = texture3d->getInternalFormat(level);
376 textureLevelWidth = texture3d->getWidth(level);
377 textureLevelHeight = texture3d->getHeight(level);
378 textureLevelDepth = texture3d->getDepth(level);
379 texture = texture3d;
380 }
381 }
382 break;
383
384 case GL_TEXTURE_2D_ARRAY:
385 {
Geoff Langaae65a42014-05-26 12:43:44 -0400386 if (static_cast<GLuint>(width) > (caps.max2DTextureSize >> level) ||
387 static_cast<GLuint>(height) > (caps.max2DTextureSize >> level) ||
388 static_cast<GLuint>(depth) > (caps.maxArrayTextureLayers >> level))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400389 {
390 return gl::error(GL_INVALID_VALUE, false);
391 }
392
393 gl::Texture2DArray *texture2darray = context->getTexture2DArray();
394 if (texture2darray)
395 {
396 textureCompressed = texture2darray->isCompressed(level);
397 textureInternalFormat = texture2darray->getInternalFormat(level);
398 textureLevelWidth = texture2darray->getWidth(level);
399 textureLevelHeight = texture2darray->getHeight(level);
Jamie Madillb8f8b892014-01-07 10:12:50 -0500400 textureLevelDepth = texture2darray->getLayers(level);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400401 texture = texture2darray;
402 }
403 }
404 break;
405
406 default:
407 return gl::error(GL_INVALID_ENUM, false);
408 }
409
410 if (!texture)
411 {
412 return gl::error(GL_INVALID_OPERATION, false);
413 }
414
415 if (texture->isImmutable() && !isSubImage)
416 {
417 return gl::error(GL_INVALID_OPERATION, false);
418 }
419
420 // Validate texture formats
421 GLenum actualInternalFormat = isSubImage ? textureInternalFormat : internalformat;
Geoff Lang5d601382014-07-22 15:14:06 -0400422 const gl::InternalFormat &actualFormatInfo = gl::GetInternalFormatInfo(actualInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400423 if (isCompressed)
424 {
Geoff Langd4f180b2013-09-24 13:57:44 -0400425 if (!ValidCompressedImageSize(context, actualInternalFormat, width, height))
426 {
427 return gl::error(GL_INVALID_OPERATION, false);
428 }
429
Geoff Lang5d601382014-07-22 15:14:06 -0400430 if (!actualFormatInfo.compressed)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400431 {
432 return gl::error(GL_INVALID_ENUM, false);
433 }
434
435 if (target == GL_TEXTURE_3D)
436 {
437 return gl::error(GL_INVALID_OPERATION, false);
438 }
439 }
440 else
441 {
Geoff Lang5d601382014-07-22 15:14:06 -0400442 if (!ValidateTexImageFormatCombination(context, internalformat, format, type))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400443 {
Geoff Lang5d601382014-07-22 15:14:06 -0400444 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400445 }
446
447 if (target == GL_TEXTURE_3D && (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL))
448 {
449 return gl::error(GL_INVALID_OPERATION, false);
450 }
451 }
452
453 // Validate sub image parameters
454 if (isSubImage)
455 {
456 if (isCompressed != textureCompressed)
457 {
458 return gl::error(GL_INVALID_OPERATION, false);
459 }
460
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400461 if (isCompressed)
462 {
463 if ((width % 4 != 0 && width != textureLevelWidth) ||
464 (height % 4 != 0 && height != textureLevelHeight))
465 {
466 return gl::error(GL_INVALID_OPERATION, false);
467 }
468 }
469
470 if (width == 0 || height == 0 || depth == 0)
471 {
472 return false;
473 }
474
475 if (xoffset < 0 || yoffset < 0 || zoffset < 0)
476 {
477 return gl::error(GL_INVALID_VALUE, false);
478 }
479
480 if (std::numeric_limits<GLsizei>::max() - xoffset < width ||
481 std::numeric_limits<GLsizei>::max() - yoffset < height ||
482 std::numeric_limits<GLsizei>::max() - zoffset < depth)
483 {
484 return gl::error(GL_INVALID_VALUE, false);
485 }
486
487 if (xoffset + width > textureLevelWidth ||
488 yoffset + height > textureLevelHeight ||
489 zoffset + depth > textureLevelDepth)
490 {
491 return gl::error(GL_INVALID_VALUE, false);
492 }
493 }
494
Jamie Madillefb2a6f2013-09-24 10:22:42 -0400495 // Check for pixel unpack buffer related API errors
Shannon Woods53a94a82014-06-24 15:20:36 -0400496 gl::Buffer *pixelUnpackBuffer = context->getState().getTargetBuffer(GL_PIXEL_UNPACK_BUFFER);
Jamie Madillefb2a6f2013-09-24 10:22:42 -0400497 if (pixelUnpackBuffer != NULL)
498 {
499 // ...the data would be unpacked from the buffer object such that the memory reads required
500 // would exceed the data store size.
501 size_t widthSize = static_cast<size_t>(width);
502 size_t heightSize = static_cast<size_t>(height);
503 size_t depthSize = static_cast<size_t>(depth);
Geoff Lang5d601382014-07-22 15:14:06 -0400504 GLenum sizedFormat = GetSizedInternalFormat(actualInternalFormat, type);
Jamie Madill6f38f822014-06-06 17:12:20 -0400505
Geoff Lang5d601382014-07-22 15:14:06 -0400506 size_t pixelBytes = static_cast<size_t>(gl::GetInternalFormatInfo(sizedFormat).pixelBytes);
Jamie Madillefb2a6f2013-09-24 10:22:42 -0400507
508 if (!rx::IsUnsignedMultiplicationSafe(widthSize, heightSize) ||
509 !rx::IsUnsignedMultiplicationSafe(widthSize * heightSize, depthSize) ||
510 !rx::IsUnsignedMultiplicationSafe(widthSize * heightSize * depthSize, pixelBytes))
511 {
512 // Overflow past the end of the buffer
513 return gl::error(GL_INVALID_OPERATION, false);
514 }
515
516 size_t copyBytes = widthSize * heightSize * depthSize * pixelBytes;
517 size_t offset = reinterpret_cast<size_t>(pixels);
518
Jamie Madill6f38f822014-06-06 17:12:20 -0400519 if (!rx::IsUnsignedAdditionSafe(offset, copyBytes) ||
Brandon Jonesd38f9262014-06-18 16:26:45 -0700520 ((offset + copyBytes) > static_cast<size_t>(pixelUnpackBuffer->getSize())))
Jamie Madillefb2a6f2013-09-24 10:22:42 -0400521 {
522 // Overflow past the end of the buffer
523 return gl::error(GL_INVALID_OPERATION, false);
524 }
525
526 // ...data is not evenly divisible into the number of bytes needed to store in memory a datum
527 // indicated by type.
Geoff Lang5d601382014-07-22 15:14:06 -0400528 size_t dataBytesPerPixel = static_cast<size_t>(gl::GetTypeInfo(type).bytes);
Jamie Madillefb2a6f2013-09-24 10:22:42 -0400529
530 if ((offset % dataBytesPerPixel) != 0)
531 {
532 return gl::error(GL_INVALID_OPERATION, false);
533 }
534
Jamie Madill7a5f7382014-03-05 15:01:24 -0500535 // ...the buffer object's data store is currently mapped.
Brandon Jonesd38f9262014-06-18 16:26:45 -0700536 if (pixelUnpackBuffer->isMapped())
Jamie Madill7a5f7382014-03-05 15:01:24 -0500537 {
538 return gl::error(GL_INVALID_OPERATION, false);
539 }
Jamie Madillefb2a6f2013-09-24 10:22:42 -0400540 }
541
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400542 return true;
543}
544
Geoff Lang5d601382014-07-22 15:14:06 -0400545struct EffectiveInternalFormatInfo
546{
547 GLenum mEffectiveFormat;
548 GLenum mDestFormat;
549 GLuint mMinRedBits;
550 GLuint mMaxRedBits;
551 GLuint mMinGreenBits;
552 GLuint mMaxGreenBits;
553 GLuint mMinBlueBits;
554 GLuint mMaxBlueBits;
555 GLuint mMinAlphaBits;
556 GLuint mMaxAlphaBits;
557
558 EffectiveInternalFormatInfo(GLenum effectiveFormat, GLenum destFormat, GLuint minRedBits, GLuint maxRedBits,
559 GLuint minGreenBits, GLuint maxGreenBits, GLuint minBlueBits, GLuint maxBlueBits,
560 GLuint minAlphaBits, GLuint maxAlphaBits)
561 : mEffectiveFormat(effectiveFormat), mDestFormat(destFormat), mMinRedBits(minRedBits),
562 mMaxRedBits(maxRedBits), mMinGreenBits(minGreenBits), mMaxGreenBits(maxGreenBits),
563 mMinBlueBits(minBlueBits), mMaxBlueBits(maxBlueBits), mMinAlphaBits(minAlphaBits),
564 mMaxAlphaBits(maxAlphaBits) {};
565};
566
567typedef std::vector<EffectiveInternalFormatInfo> EffectiveInternalFormatList;
568
569static EffectiveInternalFormatList BuildSizedEffectiveInternalFormatList()
570{
571 EffectiveInternalFormatList list;
572
573 // OpenGL ES 3.0.3 Specification, Table 3.17, pg 141: Effective internal format coresponding to destination internal format and
574 // linear source buffer component sizes.
575 // | Source channel min/max sizes |
576 // Effective Internal Format | N/A | R | G | B | A |
577 list.push_back(EffectiveInternalFormatInfo(GL_ALPHA8_EXT, GL_NONE, 0, 0, 0, 0, 0, 0, 1, 8));
578 list.push_back(EffectiveInternalFormatInfo(GL_R8, GL_NONE, 1, 8, 0, 0, 0, 0, 0, 0));
579 list.push_back(EffectiveInternalFormatInfo(GL_RG8, GL_NONE, 1, 8, 1, 8, 0, 0, 0, 0));
580 list.push_back(EffectiveInternalFormatInfo(GL_RGB565, GL_NONE, 1, 5, 1, 6, 1, 5, 0, 0));
581 list.push_back(EffectiveInternalFormatInfo(GL_RGB8, GL_NONE, 6, 8, 7, 8, 6, 8, 0, 0));
582 list.push_back(EffectiveInternalFormatInfo(GL_RGBA4, GL_NONE, 1, 4, 1, 4, 1, 4, 1, 4));
583 list.push_back(EffectiveInternalFormatInfo(GL_RGB5_A1, GL_NONE, 5, 5, 5, 5, 5, 5, 1, 1));
584 list.push_back(EffectiveInternalFormatInfo(GL_RGBA8, GL_NONE, 5, 8, 5, 8, 5, 8, 2, 8));
585 list.push_back(EffectiveInternalFormatInfo(GL_RGB10_A2, GL_NONE, 9, 10, 9, 10, 9, 10, 2, 2));
586
587 return list;
588}
589
590static EffectiveInternalFormatList BuildUnsizedEffectiveInternalFormatList()
591{
592 EffectiveInternalFormatList list;
593
594 // OpenGL ES 3.0.3 Specification, Table 3.17, pg 141: Effective internal format coresponding to destination internal format and
595 // linear source buffer component sizes.
596 // | Source channel min/max sizes |
597 // Effective Internal Format | Dest Format | R | G | B | A |
598 list.push_back(EffectiveInternalFormatInfo(GL_ALPHA8_EXT, GL_ALPHA, 0, UINT_MAX, 0, UINT_MAX, 0, UINT_MAX, 1, 8));
599 list.push_back(EffectiveInternalFormatInfo(GL_LUMINANCE8_EXT, GL_LUMINANCE, 1, 8, 0, UINT_MAX, 0, UINT_MAX, 0, UINT_MAX));
600 list.push_back(EffectiveInternalFormatInfo(GL_LUMINANCE8_ALPHA8_EXT, GL_LUMINANCE_ALPHA, 1, 8, 0, UINT_MAX, 0, UINT_MAX, 1, 8));
601 list.push_back(EffectiveInternalFormatInfo(GL_RGB565, GL_RGB, 1, 5, 1, 6, 1, 5, 0, UINT_MAX));
602 list.push_back(EffectiveInternalFormatInfo(GL_RGB8, GL_RGB, 6, 8, 7, 8, 6, 8, 0, UINT_MAX));
603 list.push_back(EffectiveInternalFormatInfo(GL_RGBA4, GL_RGBA, 1, 4, 1, 4, 1, 4, 1, 4));
604 list.push_back(EffectiveInternalFormatInfo(GL_RGB5_A1, GL_RGBA, 5, 5, 5, 5, 5, 5, 1, 1));
605 list.push_back(EffectiveInternalFormatInfo(GL_RGBA8, GL_RGBA, 5, 8, 5, 8, 5, 8, 5, 8));
606
607 return list;
608}
609
610static bool GetEffectiveInternalFormat(const InternalFormat &srcFormat, const InternalFormat &destFormat,
611 GLenum *outEffectiveFormat)
612{
613 const EffectiveInternalFormatList *list = NULL;
614 GLenum targetFormat = GL_NONE;
615
616 if (destFormat.pixelBytes > 0)
617 {
618 static const EffectiveInternalFormatList sizedList = BuildSizedEffectiveInternalFormatList();
619 list = &sizedList;
620 }
621 else
622 {
623 static const EffectiveInternalFormatList unsizedList = BuildUnsizedEffectiveInternalFormatList();
624 list = &unsizedList;
625 targetFormat = destFormat.format;
626 }
627
628 for (size_t curFormat = 0; curFormat < list->size(); ++curFormat)
629 {
630 const EffectiveInternalFormatInfo& formatInfo = list->at(curFormat);
631 if ((formatInfo.mDestFormat == targetFormat) &&
632 (formatInfo.mMinRedBits <= srcFormat.redBits && formatInfo.mMaxRedBits >= srcFormat.redBits) &&
633 (formatInfo.mMinGreenBits <= srcFormat.greenBits && formatInfo.mMaxGreenBits >= srcFormat.greenBits) &&
634 (formatInfo.mMinBlueBits <= srcFormat.blueBits && formatInfo.mMaxBlueBits >= srcFormat.blueBits) &&
635 (formatInfo.mMinAlphaBits <= srcFormat.alphaBits && formatInfo.mMaxAlphaBits >= srcFormat.alphaBits))
636 {
637 *outEffectiveFormat = formatInfo.mEffectiveFormat;
638 return true;
639 }
640 }
641
642 return false;
643}
644
645struct CopyConversion
646{
647 GLenum mTextureFormat;
648 GLenum mFramebufferFormat;
649
650 CopyConversion(GLenum textureFormat, GLenum framebufferFormat)
651 : mTextureFormat(textureFormat), mFramebufferFormat(framebufferFormat) { }
652
653 bool operator<(const CopyConversion& other) const
654 {
655 return memcmp(this, &other, sizeof(CopyConversion)) < 0;
656 }
657};
658
659typedef std::set<CopyConversion> CopyConversionSet;
660
661static CopyConversionSet BuildValidES3CopyTexImageCombinations()
662{
663 CopyConversionSet set;
664
665 // From ES 3.0.1 spec, table 3.15
666 set.insert(CopyConversion(GL_ALPHA, GL_RGBA));
667 set.insert(CopyConversion(GL_LUMINANCE, GL_RED));
668 set.insert(CopyConversion(GL_LUMINANCE, GL_RG));
669 set.insert(CopyConversion(GL_LUMINANCE, GL_RGB));
670 set.insert(CopyConversion(GL_LUMINANCE, GL_RGBA));
671 set.insert(CopyConversion(GL_LUMINANCE_ALPHA, GL_RGBA));
672 set.insert(CopyConversion(GL_RED, GL_RED));
673 set.insert(CopyConversion(GL_RED, GL_RG));
674 set.insert(CopyConversion(GL_RED, GL_RGB));
675 set.insert(CopyConversion(GL_RED, GL_RGBA));
676 set.insert(CopyConversion(GL_RG, GL_RG));
677 set.insert(CopyConversion(GL_RG, GL_RGB));
678 set.insert(CopyConversion(GL_RG, GL_RGBA));
679 set.insert(CopyConversion(GL_RGB, GL_RGB));
680 set.insert(CopyConversion(GL_RGB, GL_RGBA));
681 set.insert(CopyConversion(GL_RGBA, GL_RGBA));
682
683 // Necessary for ANGLE back-buffers
684 set.insert(CopyConversion(GL_ALPHA, GL_BGRA_EXT));
685 set.insert(CopyConversion(GL_LUMINANCE, GL_BGRA_EXT));
686 set.insert(CopyConversion(GL_LUMINANCE_ALPHA, GL_BGRA_EXT));
687 set.insert(CopyConversion(GL_RED, GL_BGRA_EXT));
688 set.insert(CopyConversion(GL_RG, GL_BGRA_EXT));
689 set.insert(CopyConversion(GL_RGB, GL_BGRA_EXT));
690 set.insert(CopyConversion(GL_RGBA, GL_BGRA_EXT));
691
692 set.insert(CopyConversion(GL_RED_INTEGER, GL_RED_INTEGER));
693 set.insert(CopyConversion(GL_RED_INTEGER, GL_RG_INTEGER));
694 set.insert(CopyConversion(GL_RED_INTEGER, GL_RGB_INTEGER));
695 set.insert(CopyConversion(GL_RED_INTEGER, GL_RGBA_INTEGER));
696 set.insert(CopyConversion(GL_RG_INTEGER, GL_RG_INTEGER));
697 set.insert(CopyConversion(GL_RG_INTEGER, GL_RGB_INTEGER));
698 set.insert(CopyConversion(GL_RG_INTEGER, GL_RGBA_INTEGER));
699 set.insert(CopyConversion(GL_RGB_INTEGER, GL_RGB_INTEGER));
700 set.insert(CopyConversion(GL_RGB_INTEGER, GL_RGBA_INTEGER));
701 set.insert(CopyConversion(GL_RGBA_INTEGER, GL_RGBA_INTEGER));
702
703 return set;
704}
705
706static bool IsValidES3CopyTexImageCombination(GLenum textureInternalFormat, GLenum frameBufferInternalFormat, GLuint readBufferHandle)
707{
708 const InternalFormat &textureInternalFormatInfo = GetInternalFormatInfo(textureInternalFormat);
709 const InternalFormat &framebufferInternalFormatInfo = GetInternalFormatInfo(frameBufferInternalFormat);
710
711 static const CopyConversionSet conversionSet = BuildValidES3CopyTexImageCombinations();
712 if (conversionSet.find(CopyConversion(textureInternalFormatInfo.format, framebufferInternalFormatInfo.format)) != conversionSet.end())
713 {
714 // Section 3.8.5 of the GLES 3.0.3 spec states that source and destination formats
715 // must both be signed, unsigned, or fixed point and both source and destinations
716 // must be either both SRGB or both not SRGB. EXT_color_buffer_float adds allowed
717 // conversion between fixed and floating point.
718
719 if ((textureInternalFormatInfo.colorEncoding == GL_SRGB) != (framebufferInternalFormatInfo.colorEncoding == GL_SRGB))
720 {
721 return false;
722 }
723
724 if (((textureInternalFormatInfo.componentType == GL_INT) != (framebufferInternalFormatInfo.componentType == GL_INT )) ||
725 ((textureInternalFormatInfo.componentType == GL_UNSIGNED_INT) != (framebufferInternalFormatInfo.componentType == GL_UNSIGNED_INT)))
726 {
727 return false;
728 }
729
730 if ((textureInternalFormatInfo.componentType == GL_UNSIGNED_NORMALIZED ||
731 textureInternalFormatInfo.componentType == GL_SIGNED_NORMALIZED ||
732 textureInternalFormatInfo.componentType == GL_FLOAT) &&
733 !(framebufferInternalFormatInfo.componentType == GL_UNSIGNED_NORMALIZED ||
734 framebufferInternalFormatInfo.componentType == GL_SIGNED_NORMALIZED ||
735 framebufferInternalFormatInfo.componentType == GL_FLOAT))
736 {
737 return false;
738 }
739
740 // GLES specification 3.0.3, sec 3.8.5, pg 139-140:
741 // The effective internal format of the source buffer is determined with the following rules applied in order:
742 // * If the source buffer is a texture or renderbuffer that was created with a sized internal format then the
743 // effective internal format is the source buffer's sized internal format.
744 // * If the source buffer is a texture that was created with an unsized base internal format, then the
745 // effective internal format is the source image array's effective internal format, as specified by table
746 // 3.12, which is determined from the <format> and <type> that were used when the source image array was
747 // specified by TexImage*.
748 // * Otherwise the effective internal format is determined by the row in table 3.17 or 3.18 where
749 // Destination Internal Format matches internalformat and where the [source channel sizes] are consistent
750 // with the values of the source buffer's [channel sizes]. Table 3.17 is used if the
751 // FRAMEBUFFER_ATTACHMENT_ENCODING is LINEAR and table 3.18 is used if the FRAMEBUFFER_ATTACHMENT_ENCODING
752 // is SRGB.
753 const InternalFormat *sourceEffectiveFormat = NULL;
754 if (readBufferHandle != 0)
755 {
756 // Not the default framebuffer, therefore the read buffer must be a user-created texture or renderbuffer
757 if (framebufferInternalFormatInfo.pixelBytes > 0)
758 {
759 sourceEffectiveFormat = &framebufferInternalFormatInfo;
760 }
761 else
762 {
763 // Renderbuffers cannot be created with an unsized internal format, so this must be an unsized-format
764 // texture. We can use the same table we use when creating textures to get its effective sized format.
765 const FormatType &typeInfo = GetFormatTypeInfo(framebufferInternalFormatInfo.format, framebufferInternalFormatInfo.type);
766 sourceEffectiveFormat = &GetInternalFormatInfo(typeInfo.internalFormat);
767 }
768 }
769 else
770 {
771 // The effective internal format must be derived from the source framebuffer's channel sizes.
772 // This is done in GetEffectiveInternalFormat for linear buffers (table 3.17)
773 if (framebufferInternalFormatInfo.colorEncoding == GL_LINEAR)
774 {
775 GLenum effectiveFormat;
776 if (GetEffectiveInternalFormat(framebufferInternalFormatInfo, textureInternalFormatInfo, &effectiveFormat))
777 {
778 sourceEffectiveFormat = &GetInternalFormatInfo(effectiveFormat);
779 }
780 else
781 {
782 return false;
783 }
784 }
785 else if (framebufferInternalFormatInfo.colorEncoding == GL_SRGB)
786 {
787 // SRGB buffers can only be copied to sized format destinations according to table 3.18
788 if ((textureInternalFormatInfo.pixelBytes > 0) &&
789 (framebufferInternalFormatInfo.redBits >= 1 && framebufferInternalFormatInfo.redBits <= 8) &&
790 (framebufferInternalFormatInfo.greenBits >= 1 && framebufferInternalFormatInfo.greenBits <= 8) &&
791 (framebufferInternalFormatInfo.blueBits >= 1 && framebufferInternalFormatInfo.blueBits <= 8) &&
792 (framebufferInternalFormatInfo.alphaBits >= 1 && framebufferInternalFormatInfo.alphaBits <= 8))
793 {
794 sourceEffectiveFormat = &GetInternalFormatInfo(GL_SRGB8_ALPHA8);
795 }
796 else
797 {
798 return false;
799 }
800 }
801 else
802 {
803 UNREACHABLE();
804 return false;
805 }
806 }
807
808 if (textureInternalFormatInfo.pixelBytes > 0)
809 {
810 // Section 3.8.5 of the GLES 3.0.3 spec, pg 139, requires that, if the destination format is sized,
811 // component sizes of the source and destination formats must exactly match
812 if (textureInternalFormatInfo.redBits != sourceEffectiveFormat->redBits ||
813 textureInternalFormatInfo.greenBits != sourceEffectiveFormat->greenBits ||
814 textureInternalFormatInfo.blueBits != sourceEffectiveFormat->blueBits ||
815 textureInternalFormatInfo.alphaBits != sourceEffectiveFormat->alphaBits)
816 {
817 return false;
818 }
819 }
820
821
822 return true; // A conversion function exists, and no rule in the specification has precluded conversion
823 // between these formats.
824 }
825
826 return false;
827}
828
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400829bool ValidateES3CopyTexImageParameters(gl::Context *context, GLenum target, GLint level, GLenum internalformat,
Jamie Madill6f38f822014-06-06 17:12:20 -0400830 bool isSubImage, GLint xoffset, GLint yoffset, GLint zoffset,
831 GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400832{
Jamie Madill560a8d82014-05-21 13:06:20 -0400833 GLenum textureInternalFormat;
834 if (!ValidateCopyTexImageParametersBase(context, target, level, internalformat, isSubImage,
Jamie Madill6f38f822014-06-06 17:12:20 -0400835 xoffset, yoffset, zoffset, x, y, width, height,
836 border, &textureInternalFormat))
Shannon Woods4dfed832014-03-17 20:03:39 -0400837 {
Jamie Madill560a8d82014-05-21 13:06:20 -0400838 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400839 }
840
Shannon Woods53a94a82014-06-24 15:20:36 -0400841 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -0400842
843 if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
844 {
845 return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
846 }
847
Shannon Woods53a94a82014-06-24 15:20:36 -0400848 if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples() != 0)
Jamie Madill3c7fa222014-06-05 13:08:51 -0400849 {
850 return gl::error(GL_INVALID_OPERATION, false);
851 }
852
853 gl::FramebufferAttachment *source = framebuffer->getReadColorbuffer();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400854 GLenum colorbufferInternalFormat = source->getInternalFormat();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400855
856 if (isSubImage)
857 {
Geoff Lang5d601382014-07-22 15:14:06 -0400858 if (!IsValidES3CopyTexImageCombination(textureInternalFormat, colorbufferInternalFormat,
859 context->getState().getReadFramebuffer()->id()))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400860 {
861 return gl::error(GL_INVALID_OPERATION, false);
862 }
863 }
Shannon Woods4d161ba2014-03-17 18:13:30 -0400864 else
865 {
Geoff Lang5d601382014-07-22 15:14:06 -0400866 if (!gl::IsValidES3CopyTexImageCombination(internalformat, colorbufferInternalFormat,
867 context->getState().getReadFramebuffer()->id()))
Shannon Woods4d161ba2014-03-17 18:13:30 -0400868 {
869 return gl::error(GL_INVALID_OPERATION, false);
870 }
871 }
872
Geoff Lang784a8fd2013-09-24 12:33:16 -0400873 // If width or height is zero, it is a no-op. Return false without setting an error.
874 return (width > 0 && height > 0);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400875}
876
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400877bool ValidateES3TexStorageParameters(gl::Context *context, GLenum target, GLsizei levels, GLenum internalformat,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400878 GLsizei width, GLsizei height, GLsizei depth)
879{
880 if (width < 1 || height < 1 || depth < 1 || levels < 1)
881 {
882 return gl::error(GL_INVALID_VALUE, false);
883 }
884
885 if (levels > gl::log2(std::max(std::max(width, height), depth)) + 1)
886 {
887 return gl::error(GL_INVALID_OPERATION, false);
888 }
889
Geoff Langaae65a42014-05-26 12:43:44 -0400890 const gl::Caps &caps = context->getCaps();
891
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400892 gl::Texture *texture = NULL;
893 switch (target)
894 {
895 case GL_TEXTURE_2D:
896 {
897 texture = context->getTexture2D();
898
Geoff Langaae65a42014-05-26 12:43:44 -0400899 if (static_cast<GLuint>(width) > caps.max2DTextureSize ||
900 static_cast<GLuint>(height) > caps.max2DTextureSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400901 {
902 return gl::error(GL_INVALID_VALUE, false);
903 }
904 }
905 break;
906
Geoff Lang01c21d22013-09-24 11:52:16 -0400907 case GL_TEXTURE_CUBE_MAP:
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400908 {
909 texture = context->getTextureCubeMap();
910
911 if (width != height)
912 {
913 return gl::error(GL_INVALID_VALUE, false);
914 }
915
Geoff Langaae65a42014-05-26 12:43:44 -0400916 if (static_cast<GLuint>(width) > caps.maxCubeMapTextureSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400917 {
918 return gl::error(GL_INVALID_VALUE, false);
919 }
920 }
921 break;
922
923 case GL_TEXTURE_3D:
924 {
925 texture = context->getTexture3D();
926
Geoff Langaae65a42014-05-26 12:43:44 -0400927 if (static_cast<GLuint>(width) > caps.max3DTextureSize ||
928 static_cast<GLuint>(height) > caps.max3DTextureSize ||
929 static_cast<GLuint>(depth) > caps.max3DTextureSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400930 {
931 return gl::error(GL_INVALID_VALUE, false);
932 }
933 }
934 break;
935
936 case GL_TEXTURE_2D_ARRAY:
937 {
938 texture = context->getTexture2DArray();
939
Geoff Langaae65a42014-05-26 12:43:44 -0400940 if (static_cast<GLuint>(width) > caps.max2DTextureSize ||
941 static_cast<GLuint>(height) > caps.max2DTextureSize ||
942 static_cast<GLuint>(depth) > caps.maxArrayTextureLayers)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400943 {
944 return gl::error(GL_INVALID_VALUE, false);
945 }
946 }
947 break;
948
949 default:
950 return gl::error(GL_INVALID_ENUM, false);
951 }
952
953 if (!texture || texture->id() == 0)
954 {
955 return gl::error(GL_INVALID_OPERATION, false);
956 }
957
958 if (texture->isImmutable())
959 {
960 return gl::error(GL_INVALID_OPERATION, false);
961 }
962
Geoff Lang5d601382014-07-22 15:14:06 -0400963 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
964 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400965 {
966 return gl::error(GL_INVALID_ENUM, false);
967 }
968
Geoff Lang5d601382014-07-22 15:14:06 -0400969 if (formatInfo.pixelBytes == 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400970 {
971 return gl::error(GL_INVALID_ENUM, false);
972 }
973
974 return true;
975}
976
Jamie Madill570f7c82014-07-03 10:38:54 -0400977bool ValidateFramebufferTextureLayer(const gl::Context *context, GLenum target, GLenum attachment,
978 GLuint texture, GLint level, GLint layer)
979{
980 if (context->getClientVersion() < 3)
981 {
982 return gl::error(GL_INVALID_OPERATION, false);
983 }
984
Jamie Madill55ec3b12014-07-03 10:38:57 -0400985 if (layer < 0)
986 {
987 return gl::error(GL_INVALID_VALUE, false);
988 }
989
990 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
991 {
992 return false;
993 }
994
995 const gl::Caps &caps = context->getCaps();
996 if (texture != 0)
997 {
998 gl::Texture *tex = context->getTexture(texture);
999 ASSERT(tex);
1000
1001 switch (tex->getTarget())
1002 {
1003 case GL_TEXTURE_2D_ARRAY:
1004 {
1005 if (level > gl::log2(caps.max2DTextureSize))
1006 {
1007 return gl::error(GL_INVALID_VALUE, false);
1008 }
1009
1010 if (static_cast<GLuint>(layer) >= caps.maxArrayTextureLayers)
1011 {
1012 return gl::error(GL_INVALID_VALUE, false);
1013 }
1014
1015 gl::Texture2DArray *texArray = static_cast<gl::Texture2DArray *>(tex);
1016 if (texArray->isCompressed(level))
1017 {
1018 return gl::error(GL_INVALID_OPERATION, false);
1019 }
1020 }
1021 break;
1022
1023 case GL_TEXTURE_3D:
1024 {
1025 if (level > gl::log2(caps.max3DTextureSize))
1026 {
1027 return gl::error(GL_INVALID_VALUE, false);
1028 }
1029
1030 if (static_cast<GLuint>(layer) >= caps.max3DTextureSize)
1031 {
1032 return gl::error(GL_INVALID_VALUE, false);
1033 }
1034
1035 gl::Texture3D *tex3d = static_cast<gl::Texture3D *>(tex);
1036 if (tex3d->isCompressed(level))
1037 {
1038 return gl::error(GL_INVALID_OPERATION, false);
1039 }
1040 }
1041 break;
1042
1043 default:
1044 return gl::error(GL_INVALID_OPERATION, false);
1045 }
1046 }
1047
1048 return true;
Jamie Madill570f7c82014-07-03 10:38:54 -04001049}
1050
Geoff Langbdc9b2f2014-04-16 14:41:54 -04001051bool ValidES3ReadFormatType(gl::Context *context, GLenum internalFormat, GLenum format, GLenum type)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001052{
Geoff Lang5d601382014-07-22 15:14:06 -04001053 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat);
1054
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001055 switch (format)
1056 {
1057 case GL_RGBA:
1058 switch (type)
1059 {
1060 case GL_UNSIGNED_BYTE:
1061 break;
1062 case GL_UNSIGNED_INT_2_10_10_10_REV:
1063 if (internalFormat != GL_RGB10_A2)
1064 {
1065 return false;
1066 }
1067 break;
Geoff Lang1ec57f82013-10-16 11:43:23 -04001068 case GL_FLOAT:
Geoff Lang5d601382014-07-22 15:14:06 -04001069 if (internalFormatInfo.componentType != GL_FLOAT)
Geoff Lang1ec57f82013-10-16 11:43:23 -04001070 {
1071 return false;
1072 }
1073 break;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001074 default:
1075 return false;
1076 }
1077 break;
1078 case GL_RGBA_INTEGER:
1079 switch (type)
1080 {
1081 case GL_INT:
Geoff Lang5d601382014-07-22 15:14:06 -04001082 if (internalFormatInfo.componentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001083 {
1084 return false;
1085 }
1086 break;
1087 case GL_UNSIGNED_INT:
Geoff Lang5d601382014-07-22 15:14:06 -04001088 if (internalFormatInfo.componentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001089 {
1090 return false;
1091 }
1092 break;
1093 default:
1094 return false;
1095 }
1096 break;
1097 case GL_BGRA_EXT:
1098 switch (type)
1099 {
1100 case GL_UNSIGNED_BYTE:
1101 case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:
1102 case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:
1103 break;
1104 default:
1105 return false;
1106 }
1107 break;
Geoff Langbdc9b2f2014-04-16 14:41:54 -04001108 case GL_RG_EXT:
1109 case GL_RED_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -04001110 if (!context->getExtensions().textureRG)
Geoff Langbdc9b2f2014-04-16 14:41:54 -04001111 {
1112 return false;
1113 }
1114 switch (type)
1115 {
1116 case GL_UNSIGNED_BYTE:
1117 break;
1118 default:
1119 return false;
1120 }
1121 break;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001122 default:
1123 return false;
1124 }
1125 return true;
1126}
1127
Geoff Lang34dbb6f2013-08-05 15:05:47 -04001128bool ValidateInvalidateFramebufferParameters(gl::Context *context, GLenum target, GLsizei numAttachments,
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001129 const GLenum* attachments)
1130{
1131 bool defaultFramebuffer = false;
1132
1133 switch (target)
1134 {
1135 case GL_DRAW_FRAMEBUFFER:
1136 case GL_FRAMEBUFFER:
Shannon Woods53a94a82014-06-24 15:20:36 -04001137 defaultFramebuffer = context->getState().getDrawFramebuffer()->id() == 0;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001138 break;
1139 case GL_READ_FRAMEBUFFER:
Shannon Woods53a94a82014-06-24 15:20:36 -04001140 defaultFramebuffer = context->getState().getReadFramebuffer()->id() == 0;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001141 break;
1142 default:
1143 return gl::error(GL_INVALID_ENUM, false);
1144 }
1145
1146 for (int i = 0; i < numAttachments; ++i)
1147 {
1148 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15)
1149 {
1150 if (defaultFramebuffer)
1151 {
1152 return gl::error(GL_INVALID_ENUM, false);
1153 }
1154
Geoff Langaae65a42014-05-26 12:43:44 -04001155 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001156 {
1157 return gl::error(GL_INVALID_OPERATION, false);
1158 }
1159 }
1160 else
1161 {
1162 switch (attachments[i])
1163 {
1164 case GL_DEPTH_ATTACHMENT:
1165 case GL_STENCIL_ATTACHMENT:
1166 case GL_DEPTH_STENCIL_ATTACHMENT:
1167 if (defaultFramebuffer)
1168 {
1169 return gl::error(GL_INVALID_ENUM, false);
1170 }
1171 break;
1172 case GL_COLOR:
1173 case GL_DEPTH:
1174 case GL_STENCIL:
1175 if (!defaultFramebuffer)
1176 {
1177 return gl::error(GL_INVALID_ENUM, false);
1178 }
1179 break;
1180 default:
1181 return gl::error(GL_INVALID_ENUM, false);
1182 }
1183 }
1184 }
1185
1186 return true;
1187}
1188
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001189bool ValidateClearBuffer(const gl::Context *context)
1190{
1191 if (context->getClientVersion() < 3)
1192 {
1193 return gl::error(GL_INVALID_OPERATION, false);
1194 }
1195
Shannon Woods53a94a82014-06-24 15:20:36 -04001196 const gl::Framebuffer *fbo = context->getState().getDrawFramebuffer();
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001197 if (!fbo || fbo->completeness() != GL_FRAMEBUFFER_COMPLETE)
1198 {
1199 return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
1200 }
1201
1202 return true;
1203}
1204
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001205}