blob: c1c13d8f909188ec408d754671d7797b83b22ce7 [file] [log] [blame]
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001//
Geoff Langcec35902014-04-16 10:52:36 -04002// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved.
Geoff Lange8ebe7f2013-08-05 15:03:13 -04003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// validationES3.cpp: Validation functions for OpenGL ES 3.0 entry point parameters
8
Geoff Lang2b5420c2014-11-19 14:20:15 -05009#include "libANGLE/validationES3.h"
10#include "libANGLE/validationES.h"
11#include "libANGLE/Context.h"
12#include "libANGLE/Texture.h"
13#include "libANGLE/Framebuffer.h"
14#include "libANGLE/Renderbuffer.h"
15#include "libANGLE/formatutils.h"
16#include "libANGLE/FramebufferAttachment.h"
Geoff Lange8ebe7f2013-08-05 15:03:13 -040017
18#include "common/mathutil.h"
Geoff Langa9be0dc2014-12-17 12:34:40 -050019#include "common/utilities.h"
Geoff Lange8ebe7f2013-08-05 15:03:13 -040020
21namespace gl
22{
23
Geoff Lang5d601382014-07-22 15:14:06 -040024struct ES3FormatCombination
25{
26 GLenum internalFormat;
27 GLenum format;
28 GLenum type;
29};
30
31bool operator<(const ES3FormatCombination& a, const ES3FormatCombination& b)
32{
33 return memcmp(&a, &b, sizeof(ES3FormatCombination)) < 0;
34}
35
36typedef std::set<ES3FormatCombination> ES3FormatCombinationSet;
37
38static inline void InsertES3FormatCombo(ES3FormatCombinationSet *set, GLenum internalFormat, GLenum format, GLenum type)
39{
40 ES3FormatCombination info;
41 info.internalFormat = internalFormat;
42 info.format = format;
43 info.type = type;
44 set->insert(info);
45}
46
47ES3FormatCombinationSet BuildES3FormatSet()
48{
49 ES3FormatCombinationSet set;
50
51 // Format combinations from ES 3.0.1 spec, table 3.2
52
53 // | Internal format | Format | Type |
54 // | | | |
55 InsertES3FormatCombo(&set, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE );
56 InsertES3FormatCombo(&set, GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_BYTE );
57 InsertES3FormatCombo(&set, GL_RGBA4, GL_RGBA, GL_UNSIGNED_BYTE );
58 InsertES3FormatCombo(&set, GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE );
59 InsertES3FormatCombo(&set, GL_RGBA8_SNORM, GL_RGBA, GL_BYTE );
60 InsertES3FormatCombo(&set, GL_RGBA4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4 );
61 InsertES3FormatCombo(&set, GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV );
62 InsertES3FormatCombo(&set, GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV );
63 InsertES3FormatCombo(&set, GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1 );
64 InsertES3FormatCombo(&set, GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT );
65 InsertES3FormatCombo(&set, GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT_OES );
66 InsertES3FormatCombo(&set, GL_RGBA32F, GL_RGBA, GL_FLOAT );
67 InsertES3FormatCombo(&set, GL_RGBA16F, GL_RGBA, GL_FLOAT );
68 InsertES3FormatCombo(&set, GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE );
69 InsertES3FormatCombo(&set, GL_RGBA8I, GL_RGBA_INTEGER, GL_BYTE );
70 InsertES3FormatCombo(&set, GL_RGBA16UI, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT );
71 InsertES3FormatCombo(&set, GL_RGBA16I, GL_RGBA_INTEGER, GL_SHORT );
72 InsertES3FormatCombo(&set, GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT );
73 InsertES3FormatCombo(&set, GL_RGBA32I, GL_RGBA_INTEGER, GL_INT );
74 InsertES3FormatCombo(&set, GL_RGB10_A2UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT_2_10_10_10_REV );
75 InsertES3FormatCombo(&set, GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE );
76 InsertES3FormatCombo(&set, GL_RGB565, GL_RGB, GL_UNSIGNED_BYTE );
77 InsertES3FormatCombo(&set, GL_SRGB8, GL_RGB, GL_UNSIGNED_BYTE );
78 InsertES3FormatCombo(&set, GL_RGB8_SNORM, GL_RGB, GL_BYTE );
79 InsertES3FormatCombo(&set, GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5 );
80 InsertES3FormatCombo(&set, GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV );
81 InsertES3FormatCombo(&set, GL_RGB9_E5, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV );
82 InsertES3FormatCombo(&set, GL_RGB16F, GL_RGB, GL_HALF_FLOAT );
83 InsertES3FormatCombo(&set, GL_RGB16F, GL_RGB, GL_HALF_FLOAT_OES );
84 InsertES3FormatCombo(&set, GL_R11F_G11F_B10F, GL_RGB, GL_HALF_FLOAT );
85 InsertES3FormatCombo(&set, GL_R11F_G11F_B10F, GL_RGB, GL_HALF_FLOAT_OES );
86 InsertES3FormatCombo(&set, GL_RGB9_E5, GL_RGB, GL_HALF_FLOAT );
87 InsertES3FormatCombo(&set, GL_RGB9_E5, GL_RGB, GL_HALF_FLOAT_OES );
88 InsertES3FormatCombo(&set, GL_RGB32F, GL_RGB, GL_FLOAT );
89 InsertES3FormatCombo(&set, GL_RGB16F, GL_RGB, GL_FLOAT );
90 InsertES3FormatCombo(&set, GL_R11F_G11F_B10F, GL_RGB, GL_FLOAT );
91 InsertES3FormatCombo(&set, GL_RGB9_E5, GL_RGB, GL_FLOAT );
92 InsertES3FormatCombo(&set, GL_RGB8UI, GL_RGB_INTEGER, GL_UNSIGNED_BYTE );
93 InsertES3FormatCombo(&set, GL_RGB8I, GL_RGB_INTEGER, GL_BYTE );
94 InsertES3FormatCombo(&set, GL_RGB16UI, GL_RGB_INTEGER, GL_UNSIGNED_SHORT );
95 InsertES3FormatCombo(&set, GL_RGB16I, GL_RGB_INTEGER, GL_SHORT );
96 InsertES3FormatCombo(&set, GL_RGB32UI, GL_RGB_INTEGER, GL_UNSIGNED_INT );
97 InsertES3FormatCombo(&set, GL_RGB32I, GL_RGB_INTEGER, GL_INT );
98 InsertES3FormatCombo(&set, GL_RG8, GL_RG, GL_UNSIGNED_BYTE );
99 InsertES3FormatCombo(&set, GL_RG8_SNORM, GL_RG, GL_BYTE );
100 InsertES3FormatCombo(&set, GL_RG16F, GL_RG, GL_HALF_FLOAT );
101 InsertES3FormatCombo(&set, GL_RG16F, GL_RG, GL_HALF_FLOAT_OES );
102 InsertES3FormatCombo(&set, GL_RG32F, GL_RG, GL_FLOAT );
103 InsertES3FormatCombo(&set, GL_RG16F, GL_RG, GL_FLOAT );
104 InsertES3FormatCombo(&set, GL_RG8UI, GL_RG_INTEGER, GL_UNSIGNED_BYTE );
105 InsertES3FormatCombo(&set, GL_RG8I, GL_RG_INTEGER, GL_BYTE );
106 InsertES3FormatCombo(&set, GL_RG16UI, GL_RG_INTEGER, GL_UNSIGNED_SHORT );
107 InsertES3FormatCombo(&set, GL_RG16I, GL_RG_INTEGER, GL_SHORT );
108 InsertES3FormatCombo(&set, GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT );
109 InsertES3FormatCombo(&set, GL_RG32I, GL_RG_INTEGER, GL_INT );
110 InsertES3FormatCombo(&set, GL_R8, GL_RED, GL_UNSIGNED_BYTE );
111 InsertES3FormatCombo(&set, GL_R8_SNORM, GL_RED, GL_BYTE );
112 InsertES3FormatCombo(&set, GL_R16F, GL_RED, GL_HALF_FLOAT );
113 InsertES3FormatCombo(&set, GL_R16F, GL_RED, GL_HALF_FLOAT_OES );
114 InsertES3FormatCombo(&set, GL_R32F, GL_RED, GL_FLOAT );
115 InsertES3FormatCombo(&set, GL_R16F, GL_RED, GL_FLOAT );
116 InsertES3FormatCombo(&set, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE );
117 InsertES3FormatCombo(&set, GL_R8I, GL_RED_INTEGER, GL_BYTE );
118 InsertES3FormatCombo(&set, GL_R16UI, GL_RED_INTEGER, GL_UNSIGNED_SHORT );
119 InsertES3FormatCombo(&set, GL_R16I, GL_RED_INTEGER, GL_SHORT );
120 InsertES3FormatCombo(&set, GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT );
121 InsertES3FormatCombo(&set, GL_R32I, GL_RED_INTEGER, GL_INT );
122
123 // Unsized formats
124 InsertES3FormatCombo(&set, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE );
125 InsertES3FormatCombo(&set, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4 );
126 InsertES3FormatCombo(&set, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1 );
127 InsertES3FormatCombo(&set, GL_RGB, GL_RGB, GL_UNSIGNED_BYTE );
128 InsertES3FormatCombo(&set, GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5 );
129 InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE );
130 InsertES3FormatCombo(&set, GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE );
131 InsertES3FormatCombo(&set, GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE );
132 InsertES3FormatCombo(&set, GL_SRGB_ALPHA_EXT, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE );
133 InsertES3FormatCombo(&set, GL_SRGB_EXT, GL_SRGB_EXT, GL_UNSIGNED_BYTE );
Jamie Madill689325c2015-07-20 14:36:53 -0400134 InsertES3FormatCombo(&set, GL_RG, GL_RG, GL_UNSIGNED_BYTE );
135 InsertES3FormatCombo(&set, GL_RG, GL_RG, GL_FLOAT );
136 InsertES3FormatCombo(&set, GL_RG, GL_RG, GL_HALF_FLOAT );
137 InsertES3FormatCombo(&set, GL_RG, GL_RG, GL_HALF_FLOAT_OES );
138 InsertES3FormatCombo(&set, GL_RED, GL_RED, GL_UNSIGNED_BYTE );
139 InsertES3FormatCombo(&set, GL_RED, GL_RED, GL_FLOAT );
140 InsertES3FormatCombo(&set, GL_RED, GL_RED, GL_HALF_FLOAT );
141 InsertES3FormatCombo(&set, GL_RED, GL_RED, GL_HALF_FLOAT_OES );
142 InsertES3FormatCombo(&set, GL_DEPTH_STENCIL, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8 );
Geoff Lang5d601382014-07-22 15:14:06 -0400143
144 // Depth stencil formats
145 InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT );
146 InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT );
147 InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT );
148 InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT );
149 InsertES3FormatCombo(&set, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8 );
150 InsertES3FormatCombo(&set, GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV);
151
152 // From GL_EXT_sRGB
153 InsertES3FormatCombo(&set, GL_SRGB8_ALPHA8_EXT, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE );
154 InsertES3FormatCombo(&set, GL_SRGB8, GL_SRGB_EXT, GL_UNSIGNED_BYTE );
155
156 // From GL_OES_texture_float
Jeff Muizelaarbb1a5be2015-12-02 12:03:46 -0500157 InsertES3FormatCombo(&set, GL_RGBA, GL_RGBA, GL_FLOAT );
158 InsertES3FormatCombo(&set, GL_RGB, GL_RGB, GL_FLOAT );
Geoff Lang5d601382014-07-22 15:14:06 -0400159 InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_FLOAT );
160 InsertES3FormatCombo(&set, GL_LUMINANCE, GL_LUMINANCE, GL_FLOAT );
161 InsertES3FormatCombo(&set, GL_ALPHA, GL_ALPHA, GL_FLOAT );
162
163 // From GL_OES_texture_half_float
164 InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT );
165 InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES );
166 InsertES3FormatCombo(&set, GL_LUMINANCE, GL_LUMINANCE, GL_HALF_FLOAT );
167 InsertES3FormatCombo(&set, GL_LUMINANCE, GL_LUMINANCE, GL_HALF_FLOAT_OES );
168 InsertES3FormatCombo(&set, GL_ALPHA, GL_ALPHA, GL_HALF_FLOAT );
169 InsertES3FormatCombo(&set, GL_ALPHA, GL_ALPHA, GL_HALF_FLOAT_OES );
170
171 // From GL_EXT_texture_format_BGRA8888
172 InsertES3FormatCombo(&set, GL_BGRA_EXT, GL_BGRA_EXT, GL_UNSIGNED_BYTE );
173
174 // From GL_EXT_texture_storage
175 // | Internal format | Format | Type |
176 // | | | |
177 InsertES3FormatCombo(&set, GL_ALPHA8_EXT, GL_ALPHA, GL_UNSIGNED_BYTE );
178 InsertES3FormatCombo(&set, GL_LUMINANCE8_EXT, GL_LUMINANCE, GL_UNSIGNED_BYTE );
179 InsertES3FormatCombo(&set, GL_LUMINANCE8_ALPHA8_EXT, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE );
180 InsertES3FormatCombo(&set, GL_ALPHA32F_EXT, GL_ALPHA, GL_FLOAT );
181 InsertES3FormatCombo(&set, GL_LUMINANCE32F_EXT, GL_LUMINANCE, GL_FLOAT );
182 InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA32F_EXT, GL_LUMINANCE_ALPHA, GL_FLOAT );
183 InsertES3FormatCombo(&set, GL_ALPHA16F_EXT, GL_ALPHA, GL_HALF_FLOAT );
184 InsertES3FormatCombo(&set, GL_ALPHA16F_EXT, GL_ALPHA, GL_HALF_FLOAT_OES );
185 InsertES3FormatCombo(&set, GL_LUMINANCE16F_EXT, GL_LUMINANCE, GL_HALF_FLOAT );
186 InsertES3FormatCombo(&set, GL_LUMINANCE16F_EXT, GL_LUMINANCE, GL_HALF_FLOAT_OES );
187 InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA16F_EXT, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT );
188 InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA16F_EXT, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES );
189
190 // From GL_EXT_texture_storage and GL_EXT_texture_format_BGRA8888
191 InsertES3FormatCombo(&set, GL_BGRA8_EXT, GL_BGRA_EXT, GL_UNSIGNED_BYTE );
192 InsertES3FormatCombo(&set, GL_BGRA4_ANGLEX, GL_BGRA_EXT, GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT);
193 InsertES3FormatCombo(&set, GL_BGRA4_ANGLEX, GL_BGRA_EXT, GL_UNSIGNED_BYTE );
194 InsertES3FormatCombo(&set, GL_BGR5_A1_ANGLEX, GL_BGRA_EXT, GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT);
195 InsertES3FormatCombo(&set, GL_BGR5_A1_ANGLEX, GL_BGRA_EXT, GL_UNSIGNED_BYTE );
196
197 // From GL_ANGLE_depth_texture
198 InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT32_OES, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT_24_8_OES );
199
Geoff Lang5d601382014-07-22 15:14:06 -0400200 return set;
201}
202
203static bool ValidateTexImageFormatCombination(gl::Context *context, GLenum internalFormat, GLenum format, GLenum type)
204{
205 // Note: dEQP 2013.4 expects an INVALID_VALUE error for TexImage3D with an invalid
206 // internal format. (dEQP-GLES3.functional.negative_api.texture.teximage3d)
Geoff Langbaadf232014-08-04 13:58:02 -0400207 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
Geoff Lang5d601382014-07-22 15:14:06 -0400208 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
209 {
Geoff Langb1196682014-07-23 13:47:29 -0400210 context->recordError(Error(GL_INVALID_ENUM));
211 return false;
Geoff Lang5d601382014-07-22 15:14:06 -0400212 }
213
214 // The type and format are valid if any supported internal format has that type and format
215 bool formatSupported = false;
216 bool typeSupported = false;
217
218 static const ES3FormatCombinationSet es3FormatSet = BuildES3FormatSet();
219 for (ES3FormatCombinationSet::const_iterator i = es3FormatSet.begin(); i != es3FormatSet.end(); i++)
220 {
221 if (i->format == format || i->type == type)
222 {
223 const gl::InternalFormat &info = gl::GetInternalFormatInfo(i->internalFormat);
224 bool supported = info.textureSupport(context->getClientVersion(), context->getExtensions());
Geoff Langbaadf232014-08-04 13:58:02 -0400225 if (supported && i->type == type)
Geoff Lang5d601382014-07-22 15:14:06 -0400226 {
227 typeSupported = true;
228 }
Geoff Langbaadf232014-08-04 13:58:02 -0400229 if (supported && i->format == format)
Geoff Lang5d601382014-07-22 15:14:06 -0400230 {
231 formatSupported = true;
232 }
Geoff Langbaadf232014-08-04 13:58:02 -0400233
234 // Early-out if both type and format are supported now
235 if (typeSupported && formatSupported)
236 {
237 break;
238 }
Geoff Lang5d601382014-07-22 15:14:06 -0400239 }
240 }
241
242 if (!typeSupported || !formatSupported)
243 {
Geoff Langb1196682014-07-23 13:47:29 -0400244 context->recordError(Error(GL_INVALID_ENUM));
245 return false;
Geoff Lang5d601382014-07-22 15:14:06 -0400246 }
247
248 // Check if this is a valid format combination to load texture data
249 ES3FormatCombination searchFormat;
250 searchFormat.internalFormat = internalFormat;
251 searchFormat.format = format;
252 searchFormat.type = type;
253
254 if (es3FormatSet.find(searchFormat) == es3FormatSet.end())
255 {
Geoff Langb1196682014-07-23 13:47:29 -0400256 context->recordError(Error(GL_INVALID_OPERATION));
257 return false;
Geoff Lang5d601382014-07-22 15:14:06 -0400258 }
259
260 return true;
261}
262
Geoff Langb1196682014-07-23 13:47:29 -0400263bool ValidateES3TexImageParameters(Context *context, GLenum target, GLint level, GLenum internalformat, bool isCompressed, bool isSubImage,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400264 GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Jamie Madillefb2a6f2013-09-24 10:22:42 -0400265 GLint border, GLenum format, GLenum type, const GLvoid *pixels)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400266{
Jamie Madill6f38f822014-06-06 17:12:20 -0400267 if (!ValidTexture2DDestinationTarget(context, target))
268 {
Geoff Langb1196682014-07-23 13:47:29 -0400269 context->recordError(Error(GL_INVALID_ENUM));
270 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -0400271 }
272
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400273 // Validate image size
Austin Kinross08528e12015-10-07 16:24:40 -0700274 if (!ValidImageSizeParameters(context, target, level, width, height, depth, isSubImage))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400275 {
Geoff Langb1196682014-07-23 13:47:29 -0400276 context->recordError(Error(GL_INVALID_VALUE));
277 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400278 }
279
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400280 // Verify zero border
281 if (border != 0)
282 {
Geoff Langb1196682014-07-23 13:47:29 -0400283 context->recordError(Error(GL_INVALID_VALUE));
284 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400285 }
286
Jamie Madill6f38f822014-06-06 17:12:20 -0400287 if (xoffset < 0 || yoffset < 0 || zoffset < 0 ||
288 std::numeric_limits<GLsizei>::max() - xoffset < width ||
289 std::numeric_limits<GLsizei>::max() - yoffset < height ||
290 std::numeric_limits<GLsizei>::max() - zoffset < depth)
291 {
Geoff Langb1196682014-07-23 13:47:29 -0400292 context->recordError(Error(GL_INVALID_VALUE));
293 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -0400294 }
295
Geoff Langaae65a42014-05-26 12:43:44 -0400296 const gl::Caps &caps = context->getCaps();
297
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400298 switch (target)
299 {
300 case GL_TEXTURE_2D:
Geoff Langa9be0dc2014-12-17 12:34:40 -0500301 if (static_cast<GLuint>(width) > (caps.max2DTextureSize >> level) ||
302 static_cast<GLuint>(height) > (caps.max2DTextureSize >> level))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400303 {
Geoff Langa9be0dc2014-12-17 12:34:40 -0500304 context->recordError(Error(GL_INVALID_VALUE));
305 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400306 }
307 break;
308
309 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
310 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
311 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
312 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
313 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
314 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
Geoff Langa9be0dc2014-12-17 12:34:40 -0500315 if (!isSubImage && width != height)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400316 {
Geoff Langa9be0dc2014-12-17 12:34:40 -0500317 context->recordError(Error(GL_INVALID_VALUE));
318 return false;
319 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400320
Geoff Langa9be0dc2014-12-17 12:34:40 -0500321 if (static_cast<GLuint>(width) > (caps.maxCubeMapTextureSize >> level))
322 {
323 context->recordError(Error(GL_INVALID_VALUE));
324 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400325 }
326 break;
327
328 case GL_TEXTURE_3D:
Geoff Langa9be0dc2014-12-17 12:34:40 -0500329 if (static_cast<GLuint>(width) > (caps.max3DTextureSize >> level) ||
330 static_cast<GLuint>(height) > (caps.max3DTextureSize >> level) ||
331 static_cast<GLuint>(depth) > (caps.max3DTextureSize >> level))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400332 {
Geoff Langa9be0dc2014-12-17 12:34:40 -0500333 context->recordError(Error(GL_INVALID_VALUE));
334 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400335 }
336 break;
337
Geoff Langa9be0dc2014-12-17 12:34:40 -0500338 case GL_TEXTURE_2D_ARRAY:
339 if (static_cast<GLuint>(width) > (caps.max2DTextureSize >> level) ||
340 static_cast<GLuint>(height) > (caps.max2DTextureSize >> level) ||
Geoff Langb92c1332015-09-04 12:54:55 -0400341 static_cast<GLuint>(depth) > caps.maxArrayTextureLayers)
Geoff Langa9be0dc2014-12-17 12:34:40 -0500342 {
343 context->recordError(Error(GL_INVALID_VALUE));
344 return false;
345 }
346 break;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400347
348 default:
Geoff Langb1196682014-07-23 13:47:29 -0400349 context->recordError(Error(GL_INVALID_ENUM));
350 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400351 }
352
Geoff Lang691e58c2014-12-19 17:03:25 -0500353 gl::Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400354 if (!texture)
355 {
Geoff Langb1196682014-07-23 13:47:29 -0400356 context->recordError(Error(GL_INVALID_OPERATION));
357 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400358 }
359
Geoff Lang69cce582015-09-17 13:20:36 -0400360 if (texture->getImmutableFormat() && !isSubImage)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400361 {
Geoff Langb1196682014-07-23 13:47:29 -0400362 context->recordError(Error(GL_INVALID_OPERATION));
363 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400364 }
365
366 // Validate texture formats
Geoff Langa9be0dc2014-12-17 12:34:40 -0500367 GLenum actualInternalFormat = isSubImage ? texture->getInternalFormat(target, level) : internalformat;
Geoff Lang5d601382014-07-22 15:14:06 -0400368 const gl::InternalFormat &actualFormatInfo = gl::GetInternalFormatInfo(actualInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400369 if (isCompressed)
370 {
tmartino7c102692015-10-02 16:43:40 -0400371 if (!actualFormatInfo.compressed)
Geoff Langd4f180b2013-09-24 13:57:44 -0400372 {
tmartino7c102692015-10-02 16:43:40 -0400373 context->recordError(Error(
374 GL_INVALID_ENUM, "internalformat is not a supported compressed internal format."));
Geoff Langb1196682014-07-23 13:47:29 -0400375 return false;
Geoff Langd4f180b2013-09-24 13:57:44 -0400376 }
377
tmartino7c102692015-10-02 16:43:40 -0400378 if (!ValidCompressedImageSize(context, actualInternalFormat, width, height))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400379 {
tmartino7c102692015-10-02 16:43:40 -0400380 context->recordError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400381 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400382 }
383
Geoff Lang839ce0b2015-10-23 13:13:12 -0400384 if (!actualFormatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
385 {
386 context->recordError(Error(GL_INVALID_ENUM));
387 return false;
388 }
389
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400390 if (target == GL_TEXTURE_3D)
391 {
Geoff Langb1196682014-07-23 13:47:29 -0400392 context->recordError(Error(GL_INVALID_OPERATION));
393 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400394 }
395 }
396 else
397 {
Geoff Langbaadf232014-08-04 13:58:02 -0400398 if (!ValidateTexImageFormatCombination(context, actualInternalFormat, format, type))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400399 {
Geoff Lang5d601382014-07-22 15:14:06 -0400400 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400401 }
402
403 if (target == GL_TEXTURE_3D && (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL))
404 {
Geoff Langb1196682014-07-23 13:47:29 -0400405 context->recordError(Error(GL_INVALID_OPERATION));
406 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400407 }
408 }
409
410 // Validate sub image parameters
411 if (isSubImage)
412 {
Geoff Langa9be0dc2014-12-17 12:34:40 -0500413 if (isCompressed != actualFormatInfo.compressed)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400414 {
Geoff Langb1196682014-07-23 13:47:29 -0400415 context->recordError(Error(GL_INVALID_OPERATION));
416 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400417 }
418
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400419 if (width == 0 || height == 0 || depth == 0)
420 {
421 return false;
422 }
423
424 if (xoffset < 0 || yoffset < 0 || zoffset < 0)
425 {
Geoff Langb1196682014-07-23 13:47:29 -0400426 context->recordError(Error(GL_INVALID_VALUE));
427 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400428 }
429
430 if (std::numeric_limits<GLsizei>::max() - xoffset < width ||
431 std::numeric_limits<GLsizei>::max() - yoffset < height ||
432 std::numeric_limits<GLsizei>::max() - zoffset < depth)
433 {
Geoff Langb1196682014-07-23 13:47:29 -0400434 context->recordError(Error(GL_INVALID_VALUE));
435 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400436 }
437
Geoff Langa9be0dc2014-12-17 12:34:40 -0500438 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
439 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
440 static_cast<size_t>(zoffset + depth) > texture->getDepth(target, level))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400441 {
Geoff Langb1196682014-07-23 13:47:29 -0400442 context->recordError(Error(GL_INVALID_VALUE));
443 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400444 }
445 }
446
Jamie Madillefb2a6f2013-09-24 10:22:42 -0400447 // Check for pixel unpack buffer related API errors
Shannon Woods53a94a82014-06-24 15:20:36 -0400448 gl::Buffer *pixelUnpackBuffer = context->getState().getTargetBuffer(GL_PIXEL_UNPACK_BUFFER);
Jamie Madillefb2a6f2013-09-24 10:22:42 -0400449 if (pixelUnpackBuffer != NULL)
450 {
451 // ...the data would be unpacked from the buffer object such that the memory reads required
452 // would exceed the data store size.
453 size_t widthSize = static_cast<size_t>(width);
454 size_t heightSize = static_cast<size_t>(height);
455 size_t depthSize = static_cast<size_t>(depth);
Geoff Lang5d601382014-07-22 15:14:06 -0400456 GLenum sizedFormat = GetSizedInternalFormat(actualInternalFormat, type);
Jamie Madill6f38f822014-06-06 17:12:20 -0400457
Geoff Lang5d601382014-07-22 15:14:06 -0400458 size_t pixelBytes = static_cast<size_t>(gl::GetInternalFormatInfo(sizedFormat).pixelBytes);
Jamie Madillefb2a6f2013-09-24 10:22:42 -0400459
460 if (!rx::IsUnsignedMultiplicationSafe(widthSize, heightSize) ||
461 !rx::IsUnsignedMultiplicationSafe(widthSize * heightSize, depthSize) ||
462 !rx::IsUnsignedMultiplicationSafe(widthSize * heightSize * depthSize, pixelBytes))
463 {
464 // Overflow past the end of the buffer
Geoff Langb1196682014-07-23 13:47:29 -0400465 context->recordError(Error(GL_INVALID_OPERATION));
466 return false;
Jamie Madillefb2a6f2013-09-24 10:22:42 -0400467 }
468
Jamie Madillc751d1e2014-10-21 17:46:29 -0400469 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedFormat);
470 size_t copyBytes = formatInfo.computeBlockSize(type, width, height);
Jamie Madillefb2a6f2013-09-24 10:22:42 -0400471 size_t offset = reinterpret_cast<size_t>(pixels);
472
Jamie Madill6f38f822014-06-06 17:12:20 -0400473 if (!rx::IsUnsignedAdditionSafe(offset, copyBytes) ||
Brandon Jonesd38f9262014-06-18 16:26:45 -0700474 ((offset + copyBytes) > static_cast<size_t>(pixelUnpackBuffer->getSize())))
Jamie Madillefb2a6f2013-09-24 10:22:42 -0400475 {
476 // Overflow past the end of the buffer
Geoff Langb1196682014-07-23 13:47:29 -0400477 context->recordError(Error(GL_INVALID_OPERATION));
478 return false;
Jamie Madillefb2a6f2013-09-24 10:22:42 -0400479 }
480
481 // ...data is not evenly divisible into the number of bytes needed to store in memory a datum
482 // indicated by type.
Jamie Madillc751d1e2014-10-21 17:46:29 -0400483 if (!isCompressed)
Jamie Madillefb2a6f2013-09-24 10:22:42 -0400484 {
Jamie Madillc751d1e2014-10-21 17:46:29 -0400485 size_t dataBytesPerPixel = static_cast<size_t>(gl::GetTypeInfo(type).bytes);
486
487 if ((offset % dataBytesPerPixel) != 0)
488 {
489 context->recordError(Error(GL_INVALID_OPERATION));
490 return false;
491 }
Jamie Madillefb2a6f2013-09-24 10:22:42 -0400492 }
493
Jamie Madill7a5f7382014-03-05 15:01:24 -0500494 // ...the buffer object's data store is currently mapped.
Brandon Jonesd38f9262014-06-18 16:26:45 -0700495 if (pixelUnpackBuffer->isMapped())
Jamie Madill7a5f7382014-03-05 15:01:24 -0500496 {
Geoff Langb1196682014-07-23 13:47:29 -0400497 context->recordError(Error(GL_INVALID_OPERATION));
498 return false;
Jamie Madill7a5f7382014-03-05 15:01:24 -0500499 }
Jamie Madillefb2a6f2013-09-24 10:22:42 -0400500 }
501
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400502 return true;
503}
504
Geoff Lang5d601382014-07-22 15:14:06 -0400505struct EffectiveInternalFormatInfo
506{
507 GLenum mEffectiveFormat;
508 GLenum mDestFormat;
509 GLuint mMinRedBits;
510 GLuint mMaxRedBits;
511 GLuint mMinGreenBits;
512 GLuint mMaxGreenBits;
513 GLuint mMinBlueBits;
514 GLuint mMaxBlueBits;
515 GLuint mMinAlphaBits;
516 GLuint mMaxAlphaBits;
517
518 EffectiveInternalFormatInfo(GLenum effectiveFormat, GLenum destFormat, GLuint minRedBits, GLuint maxRedBits,
519 GLuint minGreenBits, GLuint maxGreenBits, GLuint minBlueBits, GLuint maxBlueBits,
520 GLuint minAlphaBits, GLuint maxAlphaBits)
521 : mEffectiveFormat(effectiveFormat), mDestFormat(destFormat), mMinRedBits(minRedBits),
522 mMaxRedBits(maxRedBits), mMinGreenBits(minGreenBits), mMaxGreenBits(maxGreenBits),
523 mMinBlueBits(minBlueBits), mMaxBlueBits(maxBlueBits), mMinAlphaBits(minAlphaBits),
524 mMaxAlphaBits(maxAlphaBits) {};
525};
526
527typedef std::vector<EffectiveInternalFormatInfo> EffectiveInternalFormatList;
528
529static EffectiveInternalFormatList BuildSizedEffectiveInternalFormatList()
530{
531 EffectiveInternalFormatList list;
532
533 // OpenGL ES 3.0.3 Specification, Table 3.17, pg 141: Effective internal format coresponding to destination internal format and
534 // linear source buffer component sizes.
535 // | Source channel min/max sizes |
536 // Effective Internal Format | N/A | R | G | B | A |
537 list.push_back(EffectiveInternalFormatInfo(GL_ALPHA8_EXT, GL_NONE, 0, 0, 0, 0, 0, 0, 1, 8));
538 list.push_back(EffectiveInternalFormatInfo(GL_R8, GL_NONE, 1, 8, 0, 0, 0, 0, 0, 0));
539 list.push_back(EffectiveInternalFormatInfo(GL_RG8, GL_NONE, 1, 8, 1, 8, 0, 0, 0, 0));
540 list.push_back(EffectiveInternalFormatInfo(GL_RGB565, GL_NONE, 1, 5, 1, 6, 1, 5, 0, 0));
541 list.push_back(EffectiveInternalFormatInfo(GL_RGB8, GL_NONE, 6, 8, 7, 8, 6, 8, 0, 0));
542 list.push_back(EffectiveInternalFormatInfo(GL_RGBA4, GL_NONE, 1, 4, 1, 4, 1, 4, 1, 4));
543 list.push_back(EffectiveInternalFormatInfo(GL_RGB5_A1, GL_NONE, 5, 5, 5, 5, 5, 5, 1, 1));
544 list.push_back(EffectiveInternalFormatInfo(GL_RGBA8, GL_NONE, 5, 8, 5, 8, 5, 8, 2, 8));
545 list.push_back(EffectiveInternalFormatInfo(GL_RGB10_A2, GL_NONE, 9, 10, 9, 10, 9, 10, 2, 2));
546
547 return list;
548}
549
550static EffectiveInternalFormatList BuildUnsizedEffectiveInternalFormatList()
551{
552 EffectiveInternalFormatList list;
553
554 // OpenGL ES 3.0.3 Specification, Table 3.17, pg 141: Effective internal format coresponding to destination internal format and
555 // linear source buffer component sizes.
556 // | Source channel min/max sizes |
557 // Effective Internal Format | Dest Format | R | G | B | A |
558 list.push_back(EffectiveInternalFormatInfo(GL_ALPHA8_EXT, GL_ALPHA, 0, UINT_MAX, 0, UINT_MAX, 0, UINT_MAX, 1, 8));
559 list.push_back(EffectiveInternalFormatInfo(GL_LUMINANCE8_EXT, GL_LUMINANCE, 1, 8, 0, UINT_MAX, 0, UINT_MAX, 0, UINT_MAX));
560 list.push_back(EffectiveInternalFormatInfo(GL_LUMINANCE8_ALPHA8_EXT, GL_LUMINANCE_ALPHA, 1, 8, 0, UINT_MAX, 0, UINT_MAX, 1, 8));
561 list.push_back(EffectiveInternalFormatInfo(GL_RGB565, GL_RGB, 1, 5, 1, 6, 1, 5, 0, UINT_MAX));
562 list.push_back(EffectiveInternalFormatInfo(GL_RGB8, GL_RGB, 6, 8, 7, 8, 6, 8, 0, UINT_MAX));
563 list.push_back(EffectiveInternalFormatInfo(GL_RGBA4, GL_RGBA, 1, 4, 1, 4, 1, 4, 1, 4));
564 list.push_back(EffectiveInternalFormatInfo(GL_RGB5_A1, GL_RGBA, 5, 5, 5, 5, 5, 5, 1, 1));
565 list.push_back(EffectiveInternalFormatInfo(GL_RGBA8, GL_RGBA, 5, 8, 5, 8, 5, 8, 5, 8));
566
567 return list;
568}
569
570static bool GetEffectiveInternalFormat(const InternalFormat &srcFormat, const InternalFormat &destFormat,
571 GLenum *outEffectiveFormat)
572{
573 const EffectiveInternalFormatList *list = NULL;
574 GLenum targetFormat = GL_NONE;
575
576 if (destFormat.pixelBytes > 0)
577 {
578 static const EffectiveInternalFormatList sizedList = BuildSizedEffectiveInternalFormatList();
579 list = &sizedList;
580 }
581 else
582 {
583 static const EffectiveInternalFormatList unsizedList = BuildUnsizedEffectiveInternalFormatList();
584 list = &unsizedList;
585 targetFormat = destFormat.format;
586 }
587
588 for (size_t curFormat = 0; curFormat < list->size(); ++curFormat)
589 {
590 const EffectiveInternalFormatInfo& formatInfo = list->at(curFormat);
591 if ((formatInfo.mDestFormat == targetFormat) &&
592 (formatInfo.mMinRedBits <= srcFormat.redBits && formatInfo.mMaxRedBits >= srcFormat.redBits) &&
593 (formatInfo.mMinGreenBits <= srcFormat.greenBits && formatInfo.mMaxGreenBits >= srcFormat.greenBits) &&
594 (formatInfo.mMinBlueBits <= srcFormat.blueBits && formatInfo.mMaxBlueBits >= srcFormat.blueBits) &&
595 (formatInfo.mMinAlphaBits <= srcFormat.alphaBits && formatInfo.mMaxAlphaBits >= srcFormat.alphaBits))
596 {
597 *outEffectiveFormat = formatInfo.mEffectiveFormat;
598 return true;
599 }
600 }
601
602 return false;
603}
604
605struct CopyConversion
606{
607 GLenum mTextureFormat;
608 GLenum mFramebufferFormat;
609
610 CopyConversion(GLenum textureFormat, GLenum framebufferFormat)
611 : mTextureFormat(textureFormat), mFramebufferFormat(framebufferFormat) { }
612
613 bool operator<(const CopyConversion& other) const
614 {
615 return memcmp(this, &other, sizeof(CopyConversion)) < 0;
616 }
617};
618
619typedef std::set<CopyConversion> CopyConversionSet;
620
621static CopyConversionSet BuildValidES3CopyTexImageCombinations()
622{
623 CopyConversionSet set;
624
625 // From ES 3.0.1 spec, table 3.15
626 set.insert(CopyConversion(GL_ALPHA, GL_RGBA));
627 set.insert(CopyConversion(GL_LUMINANCE, GL_RED));
628 set.insert(CopyConversion(GL_LUMINANCE, GL_RG));
629 set.insert(CopyConversion(GL_LUMINANCE, GL_RGB));
630 set.insert(CopyConversion(GL_LUMINANCE, GL_RGBA));
631 set.insert(CopyConversion(GL_LUMINANCE_ALPHA, GL_RGBA));
632 set.insert(CopyConversion(GL_RED, GL_RED));
633 set.insert(CopyConversion(GL_RED, GL_RG));
634 set.insert(CopyConversion(GL_RED, GL_RGB));
635 set.insert(CopyConversion(GL_RED, GL_RGBA));
636 set.insert(CopyConversion(GL_RG, GL_RG));
637 set.insert(CopyConversion(GL_RG, GL_RGB));
638 set.insert(CopyConversion(GL_RG, GL_RGBA));
639 set.insert(CopyConversion(GL_RGB, GL_RGB));
640 set.insert(CopyConversion(GL_RGB, GL_RGBA));
641 set.insert(CopyConversion(GL_RGBA, GL_RGBA));
642
643 // Necessary for ANGLE back-buffers
644 set.insert(CopyConversion(GL_ALPHA, GL_BGRA_EXT));
645 set.insert(CopyConversion(GL_LUMINANCE, GL_BGRA_EXT));
646 set.insert(CopyConversion(GL_LUMINANCE_ALPHA, GL_BGRA_EXT));
647 set.insert(CopyConversion(GL_RED, GL_BGRA_EXT));
648 set.insert(CopyConversion(GL_RG, GL_BGRA_EXT));
649 set.insert(CopyConversion(GL_RGB, GL_BGRA_EXT));
650 set.insert(CopyConversion(GL_RGBA, GL_BGRA_EXT));
651
652 set.insert(CopyConversion(GL_RED_INTEGER, GL_RED_INTEGER));
653 set.insert(CopyConversion(GL_RED_INTEGER, GL_RG_INTEGER));
654 set.insert(CopyConversion(GL_RED_INTEGER, GL_RGB_INTEGER));
655 set.insert(CopyConversion(GL_RED_INTEGER, GL_RGBA_INTEGER));
656 set.insert(CopyConversion(GL_RG_INTEGER, GL_RG_INTEGER));
657 set.insert(CopyConversion(GL_RG_INTEGER, GL_RGB_INTEGER));
658 set.insert(CopyConversion(GL_RG_INTEGER, GL_RGBA_INTEGER));
659 set.insert(CopyConversion(GL_RGB_INTEGER, GL_RGB_INTEGER));
660 set.insert(CopyConversion(GL_RGB_INTEGER, GL_RGBA_INTEGER));
661 set.insert(CopyConversion(GL_RGBA_INTEGER, GL_RGBA_INTEGER));
662
663 return set;
664}
665
666static bool IsValidES3CopyTexImageCombination(GLenum textureInternalFormat, GLenum frameBufferInternalFormat, GLuint readBufferHandle)
667{
668 const InternalFormat &textureInternalFormatInfo = GetInternalFormatInfo(textureInternalFormat);
669 const InternalFormat &framebufferInternalFormatInfo = GetInternalFormatInfo(frameBufferInternalFormat);
670
671 static const CopyConversionSet conversionSet = BuildValidES3CopyTexImageCombinations();
672 if (conversionSet.find(CopyConversion(textureInternalFormatInfo.format, framebufferInternalFormatInfo.format)) != conversionSet.end())
673 {
674 // Section 3.8.5 of the GLES 3.0.3 spec states that source and destination formats
675 // must both be signed, unsigned, or fixed point and both source and destinations
676 // must be either both SRGB or both not SRGB. EXT_color_buffer_float adds allowed
677 // conversion between fixed and floating point.
678
679 if ((textureInternalFormatInfo.colorEncoding == GL_SRGB) != (framebufferInternalFormatInfo.colorEncoding == GL_SRGB))
680 {
681 return false;
682 }
683
684 if (((textureInternalFormatInfo.componentType == GL_INT) != (framebufferInternalFormatInfo.componentType == GL_INT )) ||
685 ((textureInternalFormatInfo.componentType == GL_UNSIGNED_INT) != (framebufferInternalFormatInfo.componentType == GL_UNSIGNED_INT)))
686 {
687 return false;
688 }
689
690 if ((textureInternalFormatInfo.componentType == GL_UNSIGNED_NORMALIZED ||
691 textureInternalFormatInfo.componentType == GL_SIGNED_NORMALIZED ||
692 textureInternalFormatInfo.componentType == GL_FLOAT) &&
693 !(framebufferInternalFormatInfo.componentType == GL_UNSIGNED_NORMALIZED ||
694 framebufferInternalFormatInfo.componentType == GL_SIGNED_NORMALIZED ||
695 framebufferInternalFormatInfo.componentType == GL_FLOAT))
696 {
697 return false;
698 }
699
700 // GLES specification 3.0.3, sec 3.8.5, pg 139-140:
701 // The effective internal format of the source buffer is determined with the following rules applied in order:
702 // * If the source buffer is a texture or renderbuffer that was created with a sized internal format then the
703 // effective internal format is the source buffer's sized internal format.
704 // * If the source buffer is a texture that was created with an unsized base internal format, then the
705 // effective internal format is the source image array's effective internal format, as specified by table
706 // 3.12, which is determined from the <format> and <type> that were used when the source image array was
707 // specified by TexImage*.
708 // * Otherwise the effective internal format is determined by the row in table 3.17 or 3.18 where
709 // Destination Internal Format matches internalformat and where the [source channel sizes] are consistent
710 // with the values of the source buffer's [channel sizes]. Table 3.17 is used if the
711 // FRAMEBUFFER_ATTACHMENT_ENCODING is LINEAR and table 3.18 is used if the FRAMEBUFFER_ATTACHMENT_ENCODING
712 // is SRGB.
713 const InternalFormat *sourceEffectiveFormat = NULL;
714 if (readBufferHandle != 0)
715 {
716 // Not the default framebuffer, therefore the read buffer must be a user-created texture or renderbuffer
717 if (framebufferInternalFormatInfo.pixelBytes > 0)
718 {
719 sourceEffectiveFormat = &framebufferInternalFormatInfo;
720 }
721 else
722 {
723 // Renderbuffers cannot be created with an unsized internal format, so this must be an unsized-format
724 // texture. We can use the same table we use when creating textures to get its effective sized format.
Geoff Lang051dbc72015-01-05 15:48:58 -0500725 GLenum sizedInternalFormat = GetSizedInternalFormat(framebufferInternalFormatInfo.format, framebufferInternalFormatInfo.type);
726 sourceEffectiveFormat = &GetInternalFormatInfo(sizedInternalFormat);
Geoff Lang5d601382014-07-22 15:14:06 -0400727 }
728 }
729 else
730 {
731 // The effective internal format must be derived from the source framebuffer's channel sizes.
732 // This is done in GetEffectiveInternalFormat for linear buffers (table 3.17)
733 if (framebufferInternalFormatInfo.colorEncoding == GL_LINEAR)
734 {
735 GLenum effectiveFormat;
736 if (GetEffectiveInternalFormat(framebufferInternalFormatInfo, textureInternalFormatInfo, &effectiveFormat))
737 {
738 sourceEffectiveFormat = &GetInternalFormatInfo(effectiveFormat);
739 }
740 else
741 {
742 return false;
743 }
744 }
745 else if (framebufferInternalFormatInfo.colorEncoding == GL_SRGB)
746 {
747 // SRGB buffers can only be copied to sized format destinations according to table 3.18
748 if ((textureInternalFormatInfo.pixelBytes > 0) &&
749 (framebufferInternalFormatInfo.redBits >= 1 && framebufferInternalFormatInfo.redBits <= 8) &&
750 (framebufferInternalFormatInfo.greenBits >= 1 && framebufferInternalFormatInfo.greenBits <= 8) &&
751 (framebufferInternalFormatInfo.blueBits >= 1 && framebufferInternalFormatInfo.blueBits <= 8) &&
752 (framebufferInternalFormatInfo.alphaBits >= 1 && framebufferInternalFormatInfo.alphaBits <= 8))
753 {
754 sourceEffectiveFormat = &GetInternalFormatInfo(GL_SRGB8_ALPHA8);
755 }
756 else
757 {
758 return false;
759 }
760 }
761 else
762 {
763 UNREACHABLE();
764 return false;
765 }
766 }
767
768 if (textureInternalFormatInfo.pixelBytes > 0)
769 {
770 // Section 3.8.5 of the GLES 3.0.3 spec, pg 139, requires that, if the destination format is sized,
771 // component sizes of the source and destination formats must exactly match
772 if (textureInternalFormatInfo.redBits != sourceEffectiveFormat->redBits ||
773 textureInternalFormatInfo.greenBits != sourceEffectiveFormat->greenBits ||
774 textureInternalFormatInfo.blueBits != sourceEffectiveFormat->blueBits ||
775 textureInternalFormatInfo.alphaBits != sourceEffectiveFormat->alphaBits)
776 {
777 return false;
778 }
779 }
780
781
782 return true; // A conversion function exists, and no rule in the specification has precluded conversion
783 // between these formats.
784 }
785
786 return false;
787}
788
Jamie Madillc29968b2016-01-20 11:17:23 -0500789bool ValidateES3CopyTexImageParameters(ValidationContext *context,
790 GLenum target,
791 GLint level,
792 GLenum internalformat,
793 bool isSubImage,
794 GLint xoffset,
795 GLint yoffset,
796 GLint zoffset,
797 GLint x,
798 GLint y,
799 GLsizei width,
800 GLsizei height,
801 GLint border)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400802{
Jamie Madill560a8d82014-05-21 13:06:20 -0400803 GLenum textureInternalFormat;
804 if (!ValidateCopyTexImageParametersBase(context, target, level, internalformat, isSubImage,
Jamie Madill6f38f822014-06-06 17:12:20 -0400805 xoffset, yoffset, zoffset, x, y, width, height,
806 border, &textureInternalFormat))
Shannon Woods4dfed832014-03-17 20:03:39 -0400807 {
Jamie Madill560a8d82014-05-21 13:06:20 -0400808 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400809 }
810
Jamie Madillc29968b2016-01-20 11:17:23 -0500811 const auto &state = context->getState();
812 const gl::Framebuffer *framebuffer = state.getReadFramebuffer();
813 GLuint readFramebufferID = framebuffer->id();
Jamie Madill3c7fa222014-06-05 13:08:51 -0400814
Geoff Lang748f74e2014-12-01 11:25:34 -0500815 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill3c7fa222014-06-05 13:08:51 -0400816 {
Geoff Langb1196682014-07-23 13:47:29 -0400817 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
818 return false;
Jamie Madill3c7fa222014-06-05 13:08:51 -0400819 }
820
Jamie Madillc29968b2016-01-20 11:17:23 -0500821 if (readFramebufferID != 0 && framebuffer->getSamples(context->getData()) != 0)
Jamie Madill3c7fa222014-06-05 13:08:51 -0400822 {
Geoff Langb1196682014-07-23 13:47:29 -0400823 context->recordError(Error(GL_INVALID_OPERATION));
824 return false;
Jamie Madill3c7fa222014-06-05 13:08:51 -0400825 }
826
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400827 const gl::FramebufferAttachment *source = framebuffer->getReadColorbuffer();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400828 GLenum colorbufferInternalFormat = source->getInternalFormat();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400829
830 if (isSubImage)
831 {
Geoff Lang5d601382014-07-22 15:14:06 -0400832 if (!IsValidES3CopyTexImageCombination(textureInternalFormat, colorbufferInternalFormat,
Jamie Madillc29968b2016-01-20 11:17:23 -0500833 readFramebufferID))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400834 {
Geoff Langb1196682014-07-23 13:47:29 -0400835 context->recordError(Error(GL_INVALID_OPERATION));
836 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400837 }
838 }
Shannon Woods4d161ba2014-03-17 18:13:30 -0400839 else
840 {
Geoff Lang5d601382014-07-22 15:14:06 -0400841 if (!gl::IsValidES3CopyTexImageCombination(internalformat, colorbufferInternalFormat,
Jamie Madillc29968b2016-01-20 11:17:23 -0500842 readFramebufferID))
Shannon Woods4d161ba2014-03-17 18:13:30 -0400843 {
Geoff Langb1196682014-07-23 13:47:29 -0400844 context->recordError(Error(GL_INVALID_OPERATION));
845 return false;
Shannon Woods4d161ba2014-03-17 18:13:30 -0400846 }
847 }
848
Geoff Lang784a8fd2013-09-24 12:33:16 -0400849 // If width or height is zero, it is a no-op. Return false without setting an error.
850 return (width > 0 && height > 0);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400851}
852
Geoff Langb1196682014-07-23 13:47:29 -0400853bool ValidateES3TexStorageParameters(Context *context, GLenum target, GLsizei levels, GLenum internalformat,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400854 GLsizei width, GLsizei height, GLsizei depth)
855{
856 if (width < 1 || height < 1 || depth < 1 || levels < 1)
857 {
Geoff Langb1196682014-07-23 13:47:29 -0400858 context->recordError(Error(GL_INVALID_VALUE));
859 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400860 }
861
Geoff Langb92c1332015-09-04 12:54:55 -0400862 GLsizei maxDim = std::max(width, height);
863 if (target != GL_TEXTURE_2D_ARRAY)
864 {
865 maxDim = std::max(maxDim, depth);
866 }
867
868 if (levels > gl::log2(maxDim) + 1)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400869 {
Geoff Langb1196682014-07-23 13:47:29 -0400870 context->recordError(Error(GL_INVALID_OPERATION));
871 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400872 }
873
Geoff Langaae65a42014-05-26 12:43:44 -0400874 const gl::Caps &caps = context->getCaps();
875
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400876 switch (target)
877 {
878 case GL_TEXTURE_2D:
879 {
Geoff Langaae65a42014-05-26 12:43:44 -0400880 if (static_cast<GLuint>(width) > caps.max2DTextureSize ||
881 static_cast<GLuint>(height) > caps.max2DTextureSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400882 {
Geoff Langb1196682014-07-23 13:47:29 -0400883 context->recordError(Error(GL_INVALID_VALUE));
884 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400885 }
886 }
887 break;
888
Geoff Lang01c21d22013-09-24 11:52:16 -0400889 case GL_TEXTURE_CUBE_MAP:
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400890 {
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400891 if (width != height)
892 {
Geoff Langb1196682014-07-23 13:47:29 -0400893 context->recordError(Error(GL_INVALID_VALUE));
894 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400895 }
896
Geoff Langaae65a42014-05-26 12:43:44 -0400897 if (static_cast<GLuint>(width) > caps.maxCubeMapTextureSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400898 {
Geoff Langb1196682014-07-23 13:47:29 -0400899 context->recordError(Error(GL_INVALID_VALUE));
900 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400901 }
902 }
903 break;
904
905 case GL_TEXTURE_3D:
906 {
Geoff Langaae65a42014-05-26 12:43:44 -0400907 if (static_cast<GLuint>(width) > caps.max3DTextureSize ||
908 static_cast<GLuint>(height) > caps.max3DTextureSize ||
909 static_cast<GLuint>(depth) > caps.max3DTextureSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400910 {
Geoff Langb1196682014-07-23 13:47:29 -0400911 context->recordError(Error(GL_INVALID_VALUE));
912 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400913 }
914 }
915 break;
916
917 case GL_TEXTURE_2D_ARRAY:
918 {
Geoff Langaae65a42014-05-26 12:43:44 -0400919 if (static_cast<GLuint>(width) > caps.max2DTextureSize ||
920 static_cast<GLuint>(height) > caps.max2DTextureSize ||
921 static_cast<GLuint>(depth) > caps.maxArrayTextureLayers)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400922 {
Geoff Langb1196682014-07-23 13:47:29 -0400923 context->recordError(Error(GL_INVALID_VALUE));
924 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400925 }
926 }
927 break;
928
929 default:
Geoff Langb1196682014-07-23 13:47:29 -0400930 context->recordError(Error(GL_INVALID_ENUM));
931 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400932 }
933
Geoff Lang691e58c2014-12-19 17:03:25 -0500934 gl::Texture *texture = context->getTargetTexture(target);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400935 if (!texture || texture->id() == 0)
936 {
Geoff Langb1196682014-07-23 13:47:29 -0400937 context->recordError(Error(GL_INVALID_OPERATION));
938 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400939 }
940
Geoff Lang69cce582015-09-17 13:20:36 -0400941 if (texture->getImmutableFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400942 {
Geoff Langb1196682014-07-23 13:47:29 -0400943 context->recordError(Error(GL_INVALID_OPERATION));
944 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400945 }
946
Geoff Lang5d601382014-07-22 15:14:06 -0400947 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
948 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400949 {
Geoff Langb1196682014-07-23 13:47:29 -0400950 context->recordError(Error(GL_INVALID_ENUM));
951 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400952 }
953
Geoff Lang5d601382014-07-22 15:14:06 -0400954 if (formatInfo.pixelBytes == 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400955 {
Geoff Langb1196682014-07-23 13:47:29 -0400956 context->recordError(Error(GL_INVALID_ENUM));
957 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400958 }
959
960 return true;
961}
962
Geoff Langb1196682014-07-23 13:47:29 -0400963bool ValidateFramebufferTextureLayer(Context *context, GLenum target, GLenum attachment,
Jamie Madill570f7c82014-07-03 10:38:54 -0400964 GLuint texture, GLint level, GLint layer)
965{
966 if (context->getClientVersion() < 3)
967 {
Geoff Langb1196682014-07-23 13:47:29 -0400968 context->recordError(Error(GL_INVALID_OPERATION));
969 return false;
Jamie Madill570f7c82014-07-03 10:38:54 -0400970 }
971
Jamie Madill55ec3b12014-07-03 10:38:57 -0400972 if (layer < 0)
973 {
Geoff Langb1196682014-07-23 13:47:29 -0400974 context->recordError(Error(GL_INVALID_VALUE));
975 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -0400976 }
977
978 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
979 {
980 return false;
981 }
982
983 const gl::Caps &caps = context->getCaps();
984 if (texture != 0)
985 {
986 gl::Texture *tex = context->getTexture(texture);
987 ASSERT(tex);
988
989 switch (tex->getTarget())
990 {
991 case GL_TEXTURE_2D_ARRAY:
992 {
993 if (level > gl::log2(caps.max2DTextureSize))
994 {
Geoff Langb1196682014-07-23 13:47:29 -0400995 context->recordError(Error(GL_INVALID_VALUE));
996 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -0400997 }
998
999 if (static_cast<GLuint>(layer) >= caps.maxArrayTextureLayers)
1000 {
Geoff Langb1196682014-07-23 13:47:29 -04001001 context->recordError(Error(GL_INVALID_VALUE));
1002 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001003 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001004 }
1005 break;
1006
1007 case GL_TEXTURE_3D:
1008 {
1009 if (level > gl::log2(caps.max3DTextureSize))
1010 {
Geoff Langb1196682014-07-23 13:47:29 -04001011 context->recordError(Error(GL_INVALID_VALUE));
1012 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001013 }
1014
1015 if (static_cast<GLuint>(layer) >= caps.max3DTextureSize)
1016 {
Geoff Langb1196682014-07-23 13:47:29 -04001017 context->recordError(Error(GL_INVALID_VALUE));
1018 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001019 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001020 }
1021 break;
1022
1023 default:
Geoff Langb1196682014-07-23 13:47:29 -04001024 context->recordError(Error(GL_INVALID_OPERATION));
1025 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001026 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05001027
1028 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(tex->getInternalFormat(tex->getTarget(), level));
1029 if (internalFormatInfo.compressed)
1030 {
1031 context->recordError(Error(GL_INVALID_OPERATION));
1032 return false;
1033 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001034 }
1035
1036 return true;
Jamie Madill570f7c82014-07-03 10:38:54 -04001037}
1038
Geoff Langb1196682014-07-23 13:47:29 -04001039bool ValidES3ReadFormatType(Context *context, GLenum internalFormat, GLenum format, GLenum type)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001040{
Geoff Lang5d601382014-07-22 15:14:06 -04001041 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat);
1042
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001043 switch (format)
1044 {
1045 case GL_RGBA:
1046 switch (type)
1047 {
1048 case GL_UNSIGNED_BYTE:
1049 break;
1050 case GL_UNSIGNED_INT_2_10_10_10_REV:
1051 if (internalFormat != GL_RGB10_A2)
1052 {
1053 return false;
1054 }
1055 break;
Geoff Lang1ec57f82013-10-16 11:43:23 -04001056 case GL_FLOAT:
Geoff Lang5d601382014-07-22 15:14:06 -04001057 if (internalFormatInfo.componentType != GL_FLOAT)
Geoff Lang1ec57f82013-10-16 11:43:23 -04001058 {
1059 return false;
1060 }
1061 break;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001062 default:
1063 return false;
1064 }
1065 break;
1066 case GL_RGBA_INTEGER:
1067 switch (type)
1068 {
1069 case GL_INT:
Geoff Lang5d601382014-07-22 15:14:06 -04001070 if (internalFormatInfo.componentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001071 {
1072 return false;
1073 }
1074 break;
1075 case GL_UNSIGNED_INT:
Geoff Lang5d601382014-07-22 15:14:06 -04001076 if (internalFormatInfo.componentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001077 {
1078 return false;
1079 }
1080 break;
1081 default:
1082 return false;
1083 }
1084 break;
1085 case GL_BGRA_EXT:
1086 switch (type)
1087 {
1088 case GL_UNSIGNED_BYTE:
1089 case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:
1090 case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:
1091 break;
1092 default:
1093 return false;
1094 }
1095 break;
Geoff Langbdc9b2f2014-04-16 14:41:54 -04001096 case GL_RG_EXT:
1097 case GL_RED_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -04001098 if (!context->getExtensions().textureRG)
Geoff Langbdc9b2f2014-04-16 14:41:54 -04001099 {
1100 return false;
1101 }
1102 switch (type)
1103 {
1104 case GL_UNSIGNED_BYTE:
1105 break;
1106 default:
1107 return false;
1108 }
1109 break;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001110 default:
1111 return false;
1112 }
1113 return true;
1114}
1115
Corentin Walleze0902642014-11-04 12:32:15 -08001116bool ValidateES3RenderbufferStorageParameters(gl::Context *context, GLenum target, GLsizei samples,
1117 GLenum internalformat, GLsizei width, GLsizei height)
1118{
1119 if (!ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height))
1120 {
1121 return false;
1122 }
1123
1124 //The ES3 spec(section 4.4.2) states that the internal format must be sized and not an integer format if samples is greater than zero.
1125 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1126 if ((formatInfo.componentType == GL_UNSIGNED_INT || formatInfo.componentType == GL_INT) && samples > 0)
1127 {
1128 context->recordError(Error(GL_INVALID_OPERATION));
1129 return false;
1130 }
1131
1132 // The behavior is different than the ANGLE version, which would generate a GL_OUT_OF_MEMORY.
1133 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
1134 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
1135 {
1136 context->recordError(Error(GL_INVALID_VALUE));
1137 return false;
1138 }
1139
1140 return true;
1141}
1142
Austin Kinross08332632015-05-05 13:35:47 -07001143bool ValidateInvalidateFramebuffer(Context *context, GLenum target, GLsizei numAttachments,
1144 const GLenum *attachments)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001145{
Austin Kinross08332632015-05-05 13:35:47 -07001146 if (context->getClientVersion() < 3)
1147 {
1148 context->recordError(Error(GL_INVALID_OPERATION, "Operation only supported on ES 3.0 and above"));
1149 return false;
1150 }
1151
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001152 bool defaultFramebuffer = false;
1153
1154 switch (target)
1155 {
1156 case GL_DRAW_FRAMEBUFFER:
1157 case GL_FRAMEBUFFER:
Shannon Woods53a94a82014-06-24 15:20:36 -04001158 defaultFramebuffer = context->getState().getDrawFramebuffer()->id() == 0;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001159 break;
1160 case GL_READ_FRAMEBUFFER:
Shannon Woods53a94a82014-06-24 15:20:36 -04001161 defaultFramebuffer = context->getState().getReadFramebuffer()->id() == 0;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001162 break;
1163 default:
Austin Kinross08332632015-05-05 13:35:47 -07001164 context->recordError(Error(GL_INVALID_ENUM, "Invalid framebuffer target"));
1165 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001166 }
1167
Austin Kinross08332632015-05-05 13:35:47 -07001168 return ValidateDiscardFramebufferBase(context, target, numAttachments, attachments, defaultFramebuffer);
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001169}
1170
Jamie Madillc29968b2016-01-20 11:17:23 -05001171bool ValidateClearBuffer(ValidationContext *context)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001172{
1173 if (context->getClientVersion() < 3)
1174 {
Geoff Langb1196682014-07-23 13:47:29 -04001175 context->recordError(Error(GL_INVALID_OPERATION));
1176 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001177 }
1178
Shannon Woods53a94a82014-06-24 15:20:36 -04001179 const gl::Framebuffer *fbo = context->getState().getDrawFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001180 if (!fbo || fbo->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001181 {
Geoff Langb1196682014-07-23 13:47:29 -04001182 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1183 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001184 }
1185
1186 return true;
1187}
1188
Geoff Langb1196682014-07-23 13:47:29 -04001189bool ValidateGetUniformuiv(Context *context, GLuint program, GLint location, GLuint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001190{
1191 if (context->getClientVersion() < 3)
1192 {
Geoff Langb1196682014-07-23 13:47:29 -04001193 context->recordError(Error(GL_INVALID_OPERATION));
1194 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001195 }
1196
Jamie Madill78f41802014-08-25 15:47:55 -04001197 return ValidateGetUniformBase(context, program, location);
Jamie Madill0063c512014-08-25 15:47:53 -04001198}
1199
Jamie Madillb885e572015-02-03 16:16:04 -05001200bool ValidateReadBuffer(Context *context, GLenum src)
1201{
1202 if (context->getClientVersion() < 3)
1203 {
1204 context->recordError(Error(GL_INVALID_OPERATION));
1205 return false;
1206 }
1207
1208 Framebuffer *readFBO = context->getState().getReadFramebuffer();
1209
1210 if (readFBO == nullptr)
1211 {
1212 context->recordError(gl::Error(GL_INVALID_OPERATION, "No active read framebuffer."));
1213 return false;
1214 }
1215
1216 if (src == GL_NONE)
1217 {
1218 return true;
1219 }
1220
1221 if (src != GL_BACK && (src < GL_COLOR_ATTACHMENT0 || src > GL_COLOR_ATTACHMENT15))
1222 {
1223 context->recordError(gl::Error(GL_INVALID_ENUM, "Unknown enum for 'src' in ReadBuffer"));
1224 return false;
1225 }
1226
1227 if (readFBO->id() == 0)
1228 {
1229 if (src != GL_BACK)
1230 {
1231 const char *errorMsg = "'src' must be GL_NONE or GL_BACK when reading from the default framebuffer.";
1232 context->recordError(gl::Error(GL_INVALID_OPERATION, errorMsg));
1233 return false;
1234 }
1235 }
1236 else
1237 {
1238 GLuint drawBuffer = static_cast<GLuint>(src - GL_COLOR_ATTACHMENT0);
1239
1240 if (drawBuffer >= context->getCaps().maxDrawBuffers)
1241 {
1242 const char *errorMsg = "'src' is greater than MAX_DRAW_BUFFERS.";
1243 context->recordError(gl::Error(GL_INVALID_OPERATION, errorMsg));
1244 return false;
1245 }
1246 }
1247
1248 return true;
1249}
1250
Jamie Madill86af3d22015-07-21 15:14:07 -04001251bool ValidateCompressedTexImage3D(Context *context,
1252 GLenum target,
1253 GLint level,
1254 GLenum internalformat,
1255 GLsizei width,
1256 GLsizei height,
1257 GLsizei depth,
1258 GLint border,
1259 GLsizei imageSize,
1260 const GLvoid *data)
1261{
1262 if (context->getClientVersion() < 3)
1263 {
1264 context->recordError(Error(GL_INVALID_OPERATION));
1265 return false;
1266 }
1267
1268 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
1269 if (imageSize < 0 ||
1270 static_cast<GLuint>(imageSize) !=
1271 formatInfo.computeBlockSize(GL_UNSIGNED_BYTE, width, height))
1272 {
1273 context->recordError(Error(GL_INVALID_VALUE));
1274 return false;
1275 }
1276
1277 // 3D texture target validation
1278 if (target != GL_TEXTURE_3D && target != GL_TEXTURE_2D_ARRAY)
1279 {
1280 context->recordError(
1281 Error(GL_INVALID_ENUM, "Must specify a valid 3D texture destination target"));
1282 return false;
1283 }
1284
1285 // validateES3TexImageFormat sets the error code if there is an error
1286 if (!ValidateES3TexImageParameters(context, target, level, internalformat, true, false, 0, 0, 0,
1287 width, height, depth, border, GL_NONE, GL_NONE, data))
1288 {
1289 return false;
1290 }
1291
1292 return true;
1293}
Austin Kinrossbc781f32015-10-26 09:27:38 -07001294
1295bool ValidateBindVertexArray(Context *context, GLuint array)
1296{
1297 if (context->getClientVersion() < 3)
1298 {
1299 context->recordError(Error(GL_INVALID_OPERATION));
1300 return false;
1301 }
1302
1303 return ValidateBindVertexArrayBase(context, array);
1304}
1305
1306bool ValidateDeleteVertexArrays(Context *context, GLsizei n)
1307{
1308 if (context->getClientVersion() < 3)
1309 {
1310 context->recordError(Error(GL_INVALID_OPERATION));
1311 return false;
1312 }
1313
1314 return ValidateDeleteVertexArraysBase(context, n);
1315}
1316
1317bool ValidateGenVertexArrays(Context *context, GLsizei n)
1318{
1319 if (context->getClientVersion() < 3)
1320 {
1321 context->recordError(Error(GL_INVALID_OPERATION));
1322 return false;
1323 }
1324
1325 return ValidateGenVertexArraysBase(context, n);
1326}
1327
1328bool ValidateIsVertexArray(Context *context)
1329{
1330 if (context->getClientVersion() < 3)
1331 {
1332 context->recordError(Error(GL_INVALID_OPERATION));
1333 return false;
1334 }
1335
1336 return true;
1337}
Geoff Langc5629752015-12-07 16:29:04 -05001338
1339bool ValidateProgramBinary(Context *context,
1340 GLuint program,
1341 GLenum binaryFormat,
1342 const void *binary,
1343 GLint length)
1344{
1345 if (context->getClientVersion() < 3)
1346 {
1347 context->recordError(Error(GL_INVALID_OPERATION));
1348 return false;
1349 }
1350
1351 return ValidateProgramBinaryBase(context, program, binaryFormat, binary, length);
1352}
1353
1354bool ValidateGetProgramBinary(Context *context,
1355 GLuint program,
1356 GLsizei bufSize,
1357 GLsizei *length,
1358 GLenum *binaryFormat,
1359 void *binary)
1360{
1361 if (context->getClientVersion() < 3)
1362 {
1363 context->recordError(Error(GL_INVALID_OPERATION));
1364 return false;
1365 }
1366
1367 return ValidateGetProgramBinaryBase(context, program, bufSize, length, binaryFormat, binary);
1368}
1369
1370bool ValidateProgramParameter(Context *context, GLuint program, GLenum pname, GLint value)
1371{
1372 if (context->getClientVersion() < 3)
1373 {
1374 context->recordError(Error(GL_INVALID_OPERATION));
1375 return false;
1376 }
1377
1378 if (GetValidProgram(context, program) == nullptr)
1379 {
1380 return false;
1381 }
1382
1383 switch (pname)
1384 {
1385 case GL_PROGRAM_BINARY_RETRIEVABLE_HINT:
1386 break;
1387
1388 default:
1389 context->recordError(Error(GL_INVALID_ENUM, "Invalid pname: 0x%X", pname));
1390 return false;
1391 }
1392
1393 return true;
1394}
Jamie Madillc29968b2016-01-20 11:17:23 -05001395
1396bool ValidateBlitFramebuffer(Context *context,
1397 GLint srcX0,
1398 GLint srcY0,
1399 GLint srcX1,
1400 GLint srcY1,
1401 GLint dstX0,
1402 GLint dstY0,
1403 GLint dstX1,
1404 GLint dstY1,
1405 GLbitfield mask,
1406 GLenum filter)
1407{
1408 if (context->getClientVersion() < 3)
1409 {
1410 context->recordError(Error(GL_INVALID_OPERATION));
1411 return false;
1412 }
1413
1414 return ValidateBlitFramebufferParameters(context, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0,
1415 dstX1, dstY1, mask, filter);
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001416}
Jamie Madillc29968b2016-01-20 11:17:23 -05001417
1418bool ValidateClearBufferiv(ValidationContext *context,
1419 GLenum buffer,
1420 GLint drawbuffer,
1421 const GLint *value)
1422{
1423 switch (buffer)
1424 {
1425 case GL_COLOR:
1426 if (drawbuffer < 0 ||
1427 static_cast<GLuint>(drawbuffer) >= context->getCaps().maxDrawBuffers)
1428 {
1429 context->recordError(Error(GL_INVALID_VALUE));
1430 return false;
1431 }
1432 break;
1433
1434 case GL_STENCIL:
1435 if (drawbuffer != 0)
1436 {
1437 context->recordError(Error(GL_INVALID_VALUE));
1438 return false;
1439 }
1440 break;
1441
1442 default:
1443 context->recordError(Error(GL_INVALID_ENUM));
1444 return false;
1445 }
1446
1447 return ValidateClearBuffer(context);
1448}
1449
1450bool ValidateClearBufferuiv(ValidationContext *context,
1451 GLenum buffer,
1452 GLint drawbuffer,
1453 const GLuint *value)
1454{
1455 switch (buffer)
1456 {
1457 case GL_COLOR:
1458 if (drawbuffer < 0 ||
1459 static_cast<GLuint>(drawbuffer) >= context->getCaps().maxDrawBuffers)
1460 {
1461 context->recordError(Error(GL_INVALID_VALUE));
1462 return false;
1463 }
1464 break;
1465
1466 default:
1467 context->recordError(Error(GL_INVALID_ENUM));
1468 return false;
1469 }
1470
1471 return ValidateClearBuffer(context);
1472}
1473
1474bool ValidateClearBufferfv(ValidationContext *context,
1475 GLenum buffer,
1476 GLint drawbuffer,
1477 const GLfloat *value)
1478{
1479 switch (buffer)
1480 {
1481 case GL_COLOR:
1482 if (drawbuffer < 0 ||
1483 static_cast<GLuint>(drawbuffer) >= context->getCaps().maxDrawBuffers)
1484 {
1485 context->recordError(Error(GL_INVALID_VALUE));
1486 return false;
1487 }
1488 break;
1489
1490 case GL_DEPTH:
1491 if (drawbuffer != 0)
1492 {
1493 context->recordError(Error(GL_INVALID_VALUE));
1494 return false;
1495 }
1496 break;
1497
1498 default:
1499 context->recordError(Error(GL_INVALID_ENUM));
1500 return false;
1501 }
1502
1503 return ValidateClearBuffer(context);
1504}
1505
1506bool ValidateClearBufferfi(ValidationContext *context,
1507 GLenum buffer,
1508 GLint drawbuffer,
1509 GLfloat depth,
1510 GLint stencil)
1511{
1512 switch (buffer)
1513 {
1514 case GL_DEPTH_STENCIL:
1515 if (drawbuffer != 0)
1516 {
1517 context->recordError(Error(GL_INVALID_VALUE));
1518 return false;
1519 }
1520 break;
1521
1522 default:
1523 context->recordError(Error(GL_INVALID_ENUM));
1524 return false;
1525 }
1526
1527 return ValidateClearBuffer(context);
1528}
1529
1530bool ValidateDrawBuffers(ValidationContext *context, GLsizei n, const GLenum *bufs)
1531{
1532 if (context->getClientVersion() < 3)
1533 {
1534 context->recordError(Error(GL_INVALID_OPERATION, "Context does not support GLES3."));
1535 return false;
1536 }
1537
1538 return ValidateDrawBuffersBase(context, n, bufs);
1539}
1540
1541bool ValidateCopyTexSubImage3D(Context *context,
1542 GLenum target,
1543 GLint level,
1544 GLint xoffset,
1545 GLint yoffset,
1546 GLint zoffset,
1547 GLint x,
1548 GLint y,
1549 GLsizei width,
1550 GLsizei height)
1551{
1552 if (context->getClientVersion() < 3)
1553 {
1554 context->recordError(Error(GL_INVALID_OPERATION));
1555 return false;
1556 }
1557
1558 return ValidateES3CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset,
1559 yoffset, zoffset, x, y, width, height, 0);
1560}
1561
1562} // namespace gl