blob: 97dac8b29baa863ebdde9d436844e7fbd9dc7bf3 [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
157 InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_FLOAT );
158 InsertES3FormatCombo(&set, GL_LUMINANCE, GL_LUMINANCE, GL_FLOAT );
159 InsertES3FormatCombo(&set, GL_ALPHA, GL_ALPHA, GL_FLOAT );
160
161 // From GL_OES_texture_half_float
162 InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT );
163 InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES );
164 InsertES3FormatCombo(&set, GL_LUMINANCE, GL_LUMINANCE, GL_HALF_FLOAT );
165 InsertES3FormatCombo(&set, GL_LUMINANCE, GL_LUMINANCE, GL_HALF_FLOAT_OES );
166 InsertES3FormatCombo(&set, GL_ALPHA, GL_ALPHA, GL_HALF_FLOAT );
167 InsertES3FormatCombo(&set, GL_ALPHA, GL_ALPHA, GL_HALF_FLOAT_OES );
168
169 // From GL_EXT_texture_format_BGRA8888
170 InsertES3FormatCombo(&set, GL_BGRA_EXT, GL_BGRA_EXT, GL_UNSIGNED_BYTE );
171
172 // From GL_EXT_texture_storage
173 // | Internal format | Format | Type |
174 // | | | |
175 InsertES3FormatCombo(&set, GL_ALPHA8_EXT, GL_ALPHA, GL_UNSIGNED_BYTE );
176 InsertES3FormatCombo(&set, GL_LUMINANCE8_EXT, GL_LUMINANCE, GL_UNSIGNED_BYTE );
177 InsertES3FormatCombo(&set, GL_LUMINANCE8_ALPHA8_EXT, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE );
178 InsertES3FormatCombo(&set, GL_ALPHA32F_EXT, GL_ALPHA, GL_FLOAT );
179 InsertES3FormatCombo(&set, GL_LUMINANCE32F_EXT, GL_LUMINANCE, GL_FLOAT );
180 InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA32F_EXT, GL_LUMINANCE_ALPHA, GL_FLOAT );
181 InsertES3FormatCombo(&set, GL_ALPHA16F_EXT, GL_ALPHA, GL_HALF_FLOAT );
182 InsertES3FormatCombo(&set, GL_ALPHA16F_EXT, GL_ALPHA, GL_HALF_FLOAT_OES );
183 InsertES3FormatCombo(&set, GL_LUMINANCE16F_EXT, GL_LUMINANCE, GL_HALF_FLOAT );
184 InsertES3FormatCombo(&set, GL_LUMINANCE16F_EXT, GL_LUMINANCE, GL_HALF_FLOAT_OES );
185 InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA16F_EXT, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT );
186 InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA16F_EXT, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES );
187
188 // From GL_EXT_texture_storage and GL_EXT_texture_format_BGRA8888
189 InsertES3FormatCombo(&set, GL_BGRA8_EXT, GL_BGRA_EXT, GL_UNSIGNED_BYTE );
190 InsertES3FormatCombo(&set, GL_BGRA4_ANGLEX, GL_BGRA_EXT, GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT);
191 InsertES3FormatCombo(&set, GL_BGRA4_ANGLEX, GL_BGRA_EXT, GL_UNSIGNED_BYTE );
192 InsertES3FormatCombo(&set, GL_BGR5_A1_ANGLEX, GL_BGRA_EXT, GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT);
193 InsertES3FormatCombo(&set, GL_BGR5_A1_ANGLEX, GL_BGRA_EXT, GL_UNSIGNED_BYTE );
194
195 // From GL_ANGLE_depth_texture
196 InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT32_OES, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT_24_8_OES );
197
Geoff Lang5d601382014-07-22 15:14:06 -0400198 return set;
199}
200
201static bool ValidateTexImageFormatCombination(gl::Context *context, GLenum internalFormat, GLenum format, GLenum type)
202{
203 // Note: dEQP 2013.4 expects an INVALID_VALUE error for TexImage3D with an invalid
204 // internal format. (dEQP-GLES3.functional.negative_api.texture.teximage3d)
Geoff Langbaadf232014-08-04 13:58:02 -0400205 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
Geoff Lang5d601382014-07-22 15:14:06 -0400206 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
207 {
Geoff Langb1196682014-07-23 13:47:29 -0400208 context->recordError(Error(GL_INVALID_ENUM));
209 return false;
Geoff Lang5d601382014-07-22 15:14:06 -0400210 }
211
212 // The type and format are valid if any supported internal format has that type and format
213 bool formatSupported = false;
214 bool typeSupported = false;
215
216 static const ES3FormatCombinationSet es3FormatSet = BuildES3FormatSet();
217 for (ES3FormatCombinationSet::const_iterator i = es3FormatSet.begin(); i != es3FormatSet.end(); i++)
218 {
219 if (i->format == format || i->type == type)
220 {
221 const gl::InternalFormat &info = gl::GetInternalFormatInfo(i->internalFormat);
222 bool supported = info.textureSupport(context->getClientVersion(), context->getExtensions());
Geoff Langbaadf232014-08-04 13:58:02 -0400223 if (supported && i->type == type)
Geoff Lang5d601382014-07-22 15:14:06 -0400224 {
225 typeSupported = true;
226 }
Geoff Langbaadf232014-08-04 13:58:02 -0400227 if (supported && i->format == format)
Geoff Lang5d601382014-07-22 15:14:06 -0400228 {
229 formatSupported = true;
230 }
Geoff Langbaadf232014-08-04 13:58:02 -0400231
232 // Early-out if both type and format are supported now
233 if (typeSupported && formatSupported)
234 {
235 break;
236 }
Geoff Lang5d601382014-07-22 15:14:06 -0400237 }
238 }
239
240 if (!typeSupported || !formatSupported)
241 {
Geoff Langb1196682014-07-23 13:47:29 -0400242 context->recordError(Error(GL_INVALID_ENUM));
243 return false;
Geoff Lang5d601382014-07-22 15:14:06 -0400244 }
245
246 // Check if this is a valid format combination to load texture data
247 ES3FormatCombination searchFormat;
248 searchFormat.internalFormat = internalFormat;
249 searchFormat.format = format;
250 searchFormat.type = type;
251
252 if (es3FormatSet.find(searchFormat) == es3FormatSet.end())
253 {
Geoff Langb1196682014-07-23 13:47:29 -0400254 context->recordError(Error(GL_INVALID_OPERATION));
255 return false;
Geoff Lang5d601382014-07-22 15:14:06 -0400256 }
257
258 return true;
259}
260
Geoff Langb1196682014-07-23 13:47:29 -0400261bool ValidateES3TexImageParameters(Context *context, GLenum target, GLint level, GLenum internalformat, bool isCompressed, bool isSubImage,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400262 GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Jamie Madillefb2a6f2013-09-24 10:22:42 -0400263 GLint border, GLenum format, GLenum type, const GLvoid *pixels)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400264{
Jamie Madill6f38f822014-06-06 17:12:20 -0400265 if (!ValidTexture2DDestinationTarget(context, target))
266 {
Geoff Langb1196682014-07-23 13:47:29 -0400267 context->recordError(Error(GL_INVALID_ENUM));
268 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -0400269 }
270
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400271 // Validate image size
Austin Kinross08528e12015-10-07 16:24:40 -0700272 if (!ValidImageSizeParameters(context, target, level, width, height, depth, isSubImage))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400273 {
Geoff Langb1196682014-07-23 13:47:29 -0400274 context->recordError(Error(GL_INVALID_VALUE));
275 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400276 }
277
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400278 // Verify zero border
279 if (border != 0)
280 {
Geoff Langb1196682014-07-23 13:47:29 -0400281 context->recordError(Error(GL_INVALID_VALUE));
282 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400283 }
284
Jamie Madill6f38f822014-06-06 17:12:20 -0400285 if (xoffset < 0 || yoffset < 0 || zoffset < 0 ||
286 std::numeric_limits<GLsizei>::max() - xoffset < width ||
287 std::numeric_limits<GLsizei>::max() - yoffset < height ||
288 std::numeric_limits<GLsizei>::max() - zoffset < depth)
289 {
Geoff Langb1196682014-07-23 13:47:29 -0400290 context->recordError(Error(GL_INVALID_VALUE));
291 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -0400292 }
293
Geoff Langaae65a42014-05-26 12:43:44 -0400294 const gl::Caps &caps = context->getCaps();
295
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400296 switch (target)
297 {
298 case GL_TEXTURE_2D:
Geoff Langa9be0dc2014-12-17 12:34:40 -0500299 if (static_cast<GLuint>(width) > (caps.max2DTextureSize >> level) ||
300 static_cast<GLuint>(height) > (caps.max2DTextureSize >> level))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400301 {
Geoff Langa9be0dc2014-12-17 12:34:40 -0500302 context->recordError(Error(GL_INVALID_VALUE));
303 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400304 }
305 break;
306
307 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
308 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
309 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
310 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
311 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
312 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
Geoff Langa9be0dc2014-12-17 12:34:40 -0500313 if (!isSubImage && width != height)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400314 {
Geoff Langa9be0dc2014-12-17 12:34:40 -0500315 context->recordError(Error(GL_INVALID_VALUE));
316 return false;
317 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400318
Geoff Langa9be0dc2014-12-17 12:34:40 -0500319 if (static_cast<GLuint>(width) > (caps.maxCubeMapTextureSize >> level))
320 {
321 context->recordError(Error(GL_INVALID_VALUE));
322 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400323 }
324 break;
325
326 case GL_TEXTURE_3D:
Geoff Langa9be0dc2014-12-17 12:34:40 -0500327 if (static_cast<GLuint>(width) > (caps.max3DTextureSize >> level) ||
328 static_cast<GLuint>(height) > (caps.max3DTextureSize >> level) ||
329 static_cast<GLuint>(depth) > (caps.max3DTextureSize >> level))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400330 {
Geoff Langa9be0dc2014-12-17 12:34:40 -0500331 context->recordError(Error(GL_INVALID_VALUE));
332 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400333 }
334 break;
335
Geoff Langa9be0dc2014-12-17 12:34:40 -0500336 case GL_TEXTURE_2D_ARRAY:
337 if (static_cast<GLuint>(width) > (caps.max2DTextureSize >> level) ||
338 static_cast<GLuint>(height) > (caps.max2DTextureSize >> level) ||
Geoff Langb92c1332015-09-04 12:54:55 -0400339 static_cast<GLuint>(depth) > caps.maxArrayTextureLayers)
Geoff Langa9be0dc2014-12-17 12:34:40 -0500340 {
341 context->recordError(Error(GL_INVALID_VALUE));
342 return false;
343 }
344 break;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400345
346 default:
Geoff Langb1196682014-07-23 13:47:29 -0400347 context->recordError(Error(GL_INVALID_ENUM));
348 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400349 }
350
Geoff Lang691e58c2014-12-19 17:03:25 -0500351 gl::Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400352 if (!texture)
353 {
Geoff Langb1196682014-07-23 13:47:29 -0400354 context->recordError(Error(GL_INVALID_OPERATION));
355 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400356 }
357
Geoff Lang69cce582015-09-17 13:20:36 -0400358 if (texture->getImmutableFormat() && !isSubImage)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400359 {
Geoff Langb1196682014-07-23 13:47:29 -0400360 context->recordError(Error(GL_INVALID_OPERATION));
361 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400362 }
363
364 // Validate texture formats
Geoff Langa9be0dc2014-12-17 12:34:40 -0500365 GLenum actualInternalFormat = isSubImage ? texture->getInternalFormat(target, level) : internalformat;
Geoff Lang5d601382014-07-22 15:14:06 -0400366 const gl::InternalFormat &actualFormatInfo = gl::GetInternalFormatInfo(actualInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400367 if (isCompressed)
368 {
tmartino7c102692015-10-02 16:43:40 -0400369 if (!actualFormatInfo.compressed)
Geoff Langd4f180b2013-09-24 13:57:44 -0400370 {
tmartino7c102692015-10-02 16:43:40 -0400371 context->recordError(Error(
372 GL_INVALID_ENUM, "internalformat is not a supported compressed internal format."));
Geoff Langb1196682014-07-23 13:47:29 -0400373 return false;
Geoff Langd4f180b2013-09-24 13:57:44 -0400374 }
375
tmartino7c102692015-10-02 16:43:40 -0400376 if (!ValidCompressedImageSize(context, actualInternalFormat, width, height))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400377 {
tmartino7c102692015-10-02 16:43:40 -0400378 context->recordError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400379 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400380 }
381
Geoff Lang839ce0b2015-10-23 13:13:12 -0400382 if (!actualFormatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
383 {
384 context->recordError(Error(GL_INVALID_ENUM));
385 return false;
386 }
387
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400388 if (target == GL_TEXTURE_3D)
389 {
Geoff Langb1196682014-07-23 13:47:29 -0400390 context->recordError(Error(GL_INVALID_OPERATION));
391 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400392 }
393 }
394 else
395 {
Geoff Langbaadf232014-08-04 13:58:02 -0400396 if (!ValidateTexImageFormatCombination(context, actualInternalFormat, format, type))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400397 {
Geoff Lang5d601382014-07-22 15:14:06 -0400398 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400399 }
400
401 if (target == GL_TEXTURE_3D && (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL))
402 {
Geoff Langb1196682014-07-23 13:47:29 -0400403 context->recordError(Error(GL_INVALID_OPERATION));
404 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400405 }
406 }
407
408 // Validate sub image parameters
409 if (isSubImage)
410 {
Geoff Langa9be0dc2014-12-17 12:34:40 -0500411 if (isCompressed != actualFormatInfo.compressed)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400412 {
Geoff Langb1196682014-07-23 13:47:29 -0400413 context->recordError(Error(GL_INVALID_OPERATION));
414 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400415 }
416
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400417 if (width == 0 || height == 0 || depth == 0)
418 {
419 return false;
420 }
421
422 if (xoffset < 0 || yoffset < 0 || zoffset < 0)
423 {
Geoff Langb1196682014-07-23 13:47:29 -0400424 context->recordError(Error(GL_INVALID_VALUE));
425 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400426 }
427
428 if (std::numeric_limits<GLsizei>::max() - xoffset < width ||
429 std::numeric_limits<GLsizei>::max() - yoffset < height ||
430 std::numeric_limits<GLsizei>::max() - zoffset < depth)
431 {
Geoff Langb1196682014-07-23 13:47:29 -0400432 context->recordError(Error(GL_INVALID_VALUE));
433 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400434 }
435
Geoff Langa9be0dc2014-12-17 12:34:40 -0500436 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
437 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
438 static_cast<size_t>(zoffset + depth) > texture->getDepth(target, level))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400439 {
Geoff Langb1196682014-07-23 13:47:29 -0400440 context->recordError(Error(GL_INVALID_VALUE));
441 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400442 }
443 }
444
Jamie Madillefb2a6f2013-09-24 10:22:42 -0400445 // Check for pixel unpack buffer related API errors
Shannon Woods53a94a82014-06-24 15:20:36 -0400446 gl::Buffer *pixelUnpackBuffer = context->getState().getTargetBuffer(GL_PIXEL_UNPACK_BUFFER);
Jamie Madillefb2a6f2013-09-24 10:22:42 -0400447 if (pixelUnpackBuffer != NULL)
448 {
449 // ...the data would be unpacked from the buffer object such that the memory reads required
450 // would exceed the data store size.
451 size_t widthSize = static_cast<size_t>(width);
452 size_t heightSize = static_cast<size_t>(height);
453 size_t depthSize = static_cast<size_t>(depth);
Geoff Lang5d601382014-07-22 15:14:06 -0400454 GLenum sizedFormat = GetSizedInternalFormat(actualInternalFormat, type);
Jamie Madill6f38f822014-06-06 17:12:20 -0400455
Geoff Lang5d601382014-07-22 15:14:06 -0400456 size_t pixelBytes = static_cast<size_t>(gl::GetInternalFormatInfo(sizedFormat).pixelBytes);
Jamie Madillefb2a6f2013-09-24 10:22:42 -0400457
458 if (!rx::IsUnsignedMultiplicationSafe(widthSize, heightSize) ||
459 !rx::IsUnsignedMultiplicationSafe(widthSize * heightSize, depthSize) ||
460 !rx::IsUnsignedMultiplicationSafe(widthSize * heightSize * depthSize, pixelBytes))
461 {
462 // Overflow past the end of the buffer
Geoff Langb1196682014-07-23 13:47:29 -0400463 context->recordError(Error(GL_INVALID_OPERATION));
464 return false;
Jamie Madillefb2a6f2013-09-24 10:22:42 -0400465 }
466
Jamie Madillc751d1e2014-10-21 17:46:29 -0400467 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedFormat);
468 size_t copyBytes = formatInfo.computeBlockSize(type, width, height);
Jamie Madillefb2a6f2013-09-24 10:22:42 -0400469 size_t offset = reinterpret_cast<size_t>(pixels);
470
Jamie Madill6f38f822014-06-06 17:12:20 -0400471 if (!rx::IsUnsignedAdditionSafe(offset, copyBytes) ||
Brandon Jonesd38f9262014-06-18 16:26:45 -0700472 ((offset + copyBytes) > static_cast<size_t>(pixelUnpackBuffer->getSize())))
Jamie Madillefb2a6f2013-09-24 10:22:42 -0400473 {
474 // Overflow past the end of the buffer
Geoff Langb1196682014-07-23 13:47:29 -0400475 context->recordError(Error(GL_INVALID_OPERATION));
476 return false;
Jamie Madillefb2a6f2013-09-24 10:22:42 -0400477 }
478
479 // ...data is not evenly divisible into the number of bytes needed to store in memory a datum
480 // indicated by type.
Jamie Madillc751d1e2014-10-21 17:46:29 -0400481 if (!isCompressed)
Jamie Madillefb2a6f2013-09-24 10:22:42 -0400482 {
Jamie Madillc751d1e2014-10-21 17:46:29 -0400483 size_t dataBytesPerPixel = static_cast<size_t>(gl::GetTypeInfo(type).bytes);
484
485 if ((offset % dataBytesPerPixel) != 0)
486 {
487 context->recordError(Error(GL_INVALID_OPERATION));
488 return false;
489 }
Jamie Madillefb2a6f2013-09-24 10:22:42 -0400490 }
491
Jamie Madill7a5f7382014-03-05 15:01:24 -0500492 // ...the buffer object's data store is currently mapped.
Brandon Jonesd38f9262014-06-18 16:26:45 -0700493 if (pixelUnpackBuffer->isMapped())
Jamie Madill7a5f7382014-03-05 15:01:24 -0500494 {
Geoff Langb1196682014-07-23 13:47:29 -0400495 context->recordError(Error(GL_INVALID_OPERATION));
496 return false;
Jamie Madill7a5f7382014-03-05 15:01:24 -0500497 }
Jamie Madillefb2a6f2013-09-24 10:22:42 -0400498 }
499
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400500 return true;
501}
502
Geoff Lang5d601382014-07-22 15:14:06 -0400503struct EffectiveInternalFormatInfo
504{
505 GLenum mEffectiveFormat;
506 GLenum mDestFormat;
507 GLuint mMinRedBits;
508 GLuint mMaxRedBits;
509 GLuint mMinGreenBits;
510 GLuint mMaxGreenBits;
511 GLuint mMinBlueBits;
512 GLuint mMaxBlueBits;
513 GLuint mMinAlphaBits;
514 GLuint mMaxAlphaBits;
515
516 EffectiveInternalFormatInfo(GLenum effectiveFormat, GLenum destFormat, GLuint minRedBits, GLuint maxRedBits,
517 GLuint minGreenBits, GLuint maxGreenBits, GLuint minBlueBits, GLuint maxBlueBits,
518 GLuint minAlphaBits, GLuint maxAlphaBits)
519 : mEffectiveFormat(effectiveFormat), mDestFormat(destFormat), mMinRedBits(minRedBits),
520 mMaxRedBits(maxRedBits), mMinGreenBits(minGreenBits), mMaxGreenBits(maxGreenBits),
521 mMinBlueBits(minBlueBits), mMaxBlueBits(maxBlueBits), mMinAlphaBits(minAlphaBits),
522 mMaxAlphaBits(maxAlphaBits) {};
523};
524
525typedef std::vector<EffectiveInternalFormatInfo> EffectiveInternalFormatList;
526
527static EffectiveInternalFormatList BuildSizedEffectiveInternalFormatList()
528{
529 EffectiveInternalFormatList list;
530
531 // OpenGL ES 3.0.3 Specification, Table 3.17, pg 141: Effective internal format coresponding to destination internal format and
532 // linear source buffer component sizes.
533 // | Source channel min/max sizes |
534 // Effective Internal Format | N/A | R | G | B | A |
535 list.push_back(EffectiveInternalFormatInfo(GL_ALPHA8_EXT, GL_NONE, 0, 0, 0, 0, 0, 0, 1, 8));
536 list.push_back(EffectiveInternalFormatInfo(GL_R8, GL_NONE, 1, 8, 0, 0, 0, 0, 0, 0));
537 list.push_back(EffectiveInternalFormatInfo(GL_RG8, GL_NONE, 1, 8, 1, 8, 0, 0, 0, 0));
538 list.push_back(EffectiveInternalFormatInfo(GL_RGB565, GL_NONE, 1, 5, 1, 6, 1, 5, 0, 0));
539 list.push_back(EffectiveInternalFormatInfo(GL_RGB8, GL_NONE, 6, 8, 7, 8, 6, 8, 0, 0));
540 list.push_back(EffectiveInternalFormatInfo(GL_RGBA4, GL_NONE, 1, 4, 1, 4, 1, 4, 1, 4));
541 list.push_back(EffectiveInternalFormatInfo(GL_RGB5_A1, GL_NONE, 5, 5, 5, 5, 5, 5, 1, 1));
542 list.push_back(EffectiveInternalFormatInfo(GL_RGBA8, GL_NONE, 5, 8, 5, 8, 5, 8, 2, 8));
543 list.push_back(EffectiveInternalFormatInfo(GL_RGB10_A2, GL_NONE, 9, 10, 9, 10, 9, 10, 2, 2));
544
545 return list;
546}
547
548static EffectiveInternalFormatList BuildUnsizedEffectiveInternalFormatList()
549{
550 EffectiveInternalFormatList list;
551
552 // OpenGL ES 3.0.3 Specification, Table 3.17, pg 141: Effective internal format coresponding to destination internal format and
553 // linear source buffer component sizes.
554 // | Source channel min/max sizes |
555 // Effective Internal Format | Dest Format | R | G | B | A |
556 list.push_back(EffectiveInternalFormatInfo(GL_ALPHA8_EXT, GL_ALPHA, 0, UINT_MAX, 0, UINT_MAX, 0, UINT_MAX, 1, 8));
557 list.push_back(EffectiveInternalFormatInfo(GL_LUMINANCE8_EXT, GL_LUMINANCE, 1, 8, 0, UINT_MAX, 0, UINT_MAX, 0, UINT_MAX));
558 list.push_back(EffectiveInternalFormatInfo(GL_LUMINANCE8_ALPHA8_EXT, GL_LUMINANCE_ALPHA, 1, 8, 0, UINT_MAX, 0, UINT_MAX, 1, 8));
559 list.push_back(EffectiveInternalFormatInfo(GL_RGB565, GL_RGB, 1, 5, 1, 6, 1, 5, 0, UINT_MAX));
560 list.push_back(EffectiveInternalFormatInfo(GL_RGB8, GL_RGB, 6, 8, 7, 8, 6, 8, 0, UINT_MAX));
561 list.push_back(EffectiveInternalFormatInfo(GL_RGBA4, GL_RGBA, 1, 4, 1, 4, 1, 4, 1, 4));
562 list.push_back(EffectiveInternalFormatInfo(GL_RGB5_A1, GL_RGBA, 5, 5, 5, 5, 5, 5, 1, 1));
563 list.push_back(EffectiveInternalFormatInfo(GL_RGBA8, GL_RGBA, 5, 8, 5, 8, 5, 8, 5, 8));
564
565 return list;
566}
567
568static bool GetEffectiveInternalFormat(const InternalFormat &srcFormat, const InternalFormat &destFormat,
569 GLenum *outEffectiveFormat)
570{
571 const EffectiveInternalFormatList *list = NULL;
572 GLenum targetFormat = GL_NONE;
573
574 if (destFormat.pixelBytes > 0)
575 {
576 static const EffectiveInternalFormatList sizedList = BuildSizedEffectiveInternalFormatList();
577 list = &sizedList;
578 }
579 else
580 {
581 static const EffectiveInternalFormatList unsizedList = BuildUnsizedEffectiveInternalFormatList();
582 list = &unsizedList;
583 targetFormat = destFormat.format;
584 }
585
586 for (size_t curFormat = 0; curFormat < list->size(); ++curFormat)
587 {
588 const EffectiveInternalFormatInfo& formatInfo = list->at(curFormat);
589 if ((formatInfo.mDestFormat == targetFormat) &&
590 (formatInfo.mMinRedBits <= srcFormat.redBits && formatInfo.mMaxRedBits >= srcFormat.redBits) &&
591 (formatInfo.mMinGreenBits <= srcFormat.greenBits && formatInfo.mMaxGreenBits >= srcFormat.greenBits) &&
592 (formatInfo.mMinBlueBits <= srcFormat.blueBits && formatInfo.mMaxBlueBits >= srcFormat.blueBits) &&
593 (formatInfo.mMinAlphaBits <= srcFormat.alphaBits && formatInfo.mMaxAlphaBits >= srcFormat.alphaBits))
594 {
595 *outEffectiveFormat = formatInfo.mEffectiveFormat;
596 return true;
597 }
598 }
599
600 return false;
601}
602
603struct CopyConversion
604{
605 GLenum mTextureFormat;
606 GLenum mFramebufferFormat;
607
608 CopyConversion(GLenum textureFormat, GLenum framebufferFormat)
609 : mTextureFormat(textureFormat), mFramebufferFormat(framebufferFormat) { }
610
611 bool operator<(const CopyConversion& other) const
612 {
613 return memcmp(this, &other, sizeof(CopyConversion)) < 0;
614 }
615};
616
617typedef std::set<CopyConversion> CopyConversionSet;
618
619static CopyConversionSet BuildValidES3CopyTexImageCombinations()
620{
621 CopyConversionSet set;
622
623 // From ES 3.0.1 spec, table 3.15
624 set.insert(CopyConversion(GL_ALPHA, GL_RGBA));
625 set.insert(CopyConversion(GL_LUMINANCE, GL_RED));
626 set.insert(CopyConversion(GL_LUMINANCE, GL_RG));
627 set.insert(CopyConversion(GL_LUMINANCE, GL_RGB));
628 set.insert(CopyConversion(GL_LUMINANCE, GL_RGBA));
629 set.insert(CopyConversion(GL_LUMINANCE_ALPHA, GL_RGBA));
630 set.insert(CopyConversion(GL_RED, GL_RED));
631 set.insert(CopyConversion(GL_RED, GL_RG));
632 set.insert(CopyConversion(GL_RED, GL_RGB));
633 set.insert(CopyConversion(GL_RED, GL_RGBA));
634 set.insert(CopyConversion(GL_RG, GL_RG));
635 set.insert(CopyConversion(GL_RG, GL_RGB));
636 set.insert(CopyConversion(GL_RG, GL_RGBA));
637 set.insert(CopyConversion(GL_RGB, GL_RGB));
638 set.insert(CopyConversion(GL_RGB, GL_RGBA));
639 set.insert(CopyConversion(GL_RGBA, GL_RGBA));
640
641 // Necessary for ANGLE back-buffers
642 set.insert(CopyConversion(GL_ALPHA, GL_BGRA_EXT));
643 set.insert(CopyConversion(GL_LUMINANCE, GL_BGRA_EXT));
644 set.insert(CopyConversion(GL_LUMINANCE_ALPHA, GL_BGRA_EXT));
645 set.insert(CopyConversion(GL_RED, GL_BGRA_EXT));
646 set.insert(CopyConversion(GL_RG, GL_BGRA_EXT));
647 set.insert(CopyConversion(GL_RGB, GL_BGRA_EXT));
648 set.insert(CopyConversion(GL_RGBA, GL_BGRA_EXT));
649
650 set.insert(CopyConversion(GL_RED_INTEGER, GL_RED_INTEGER));
651 set.insert(CopyConversion(GL_RED_INTEGER, GL_RG_INTEGER));
652 set.insert(CopyConversion(GL_RED_INTEGER, GL_RGB_INTEGER));
653 set.insert(CopyConversion(GL_RED_INTEGER, GL_RGBA_INTEGER));
654 set.insert(CopyConversion(GL_RG_INTEGER, GL_RG_INTEGER));
655 set.insert(CopyConversion(GL_RG_INTEGER, GL_RGB_INTEGER));
656 set.insert(CopyConversion(GL_RG_INTEGER, GL_RGBA_INTEGER));
657 set.insert(CopyConversion(GL_RGB_INTEGER, GL_RGB_INTEGER));
658 set.insert(CopyConversion(GL_RGB_INTEGER, GL_RGBA_INTEGER));
659 set.insert(CopyConversion(GL_RGBA_INTEGER, GL_RGBA_INTEGER));
660
661 return set;
662}
663
664static bool IsValidES3CopyTexImageCombination(GLenum textureInternalFormat, GLenum frameBufferInternalFormat, GLuint readBufferHandle)
665{
666 const InternalFormat &textureInternalFormatInfo = GetInternalFormatInfo(textureInternalFormat);
667 const InternalFormat &framebufferInternalFormatInfo = GetInternalFormatInfo(frameBufferInternalFormat);
668
669 static const CopyConversionSet conversionSet = BuildValidES3CopyTexImageCombinations();
670 if (conversionSet.find(CopyConversion(textureInternalFormatInfo.format, framebufferInternalFormatInfo.format)) != conversionSet.end())
671 {
672 // Section 3.8.5 of the GLES 3.0.3 spec states that source and destination formats
673 // must both be signed, unsigned, or fixed point and both source and destinations
674 // must be either both SRGB or both not SRGB. EXT_color_buffer_float adds allowed
675 // conversion between fixed and floating point.
676
677 if ((textureInternalFormatInfo.colorEncoding == GL_SRGB) != (framebufferInternalFormatInfo.colorEncoding == GL_SRGB))
678 {
679 return false;
680 }
681
682 if (((textureInternalFormatInfo.componentType == GL_INT) != (framebufferInternalFormatInfo.componentType == GL_INT )) ||
683 ((textureInternalFormatInfo.componentType == GL_UNSIGNED_INT) != (framebufferInternalFormatInfo.componentType == GL_UNSIGNED_INT)))
684 {
685 return false;
686 }
687
688 if ((textureInternalFormatInfo.componentType == GL_UNSIGNED_NORMALIZED ||
689 textureInternalFormatInfo.componentType == GL_SIGNED_NORMALIZED ||
690 textureInternalFormatInfo.componentType == GL_FLOAT) &&
691 !(framebufferInternalFormatInfo.componentType == GL_UNSIGNED_NORMALIZED ||
692 framebufferInternalFormatInfo.componentType == GL_SIGNED_NORMALIZED ||
693 framebufferInternalFormatInfo.componentType == GL_FLOAT))
694 {
695 return false;
696 }
697
698 // GLES specification 3.0.3, sec 3.8.5, pg 139-140:
699 // The effective internal format of the source buffer is determined with the following rules applied in order:
700 // * If the source buffer is a texture or renderbuffer that was created with a sized internal format then the
701 // effective internal format is the source buffer's sized internal format.
702 // * If the source buffer is a texture that was created with an unsized base internal format, then the
703 // effective internal format is the source image array's effective internal format, as specified by table
704 // 3.12, which is determined from the <format> and <type> that were used when the source image array was
705 // specified by TexImage*.
706 // * Otherwise the effective internal format is determined by the row in table 3.17 or 3.18 where
707 // Destination Internal Format matches internalformat and where the [source channel sizes] are consistent
708 // with the values of the source buffer's [channel sizes]. Table 3.17 is used if the
709 // FRAMEBUFFER_ATTACHMENT_ENCODING is LINEAR and table 3.18 is used if the FRAMEBUFFER_ATTACHMENT_ENCODING
710 // is SRGB.
711 const InternalFormat *sourceEffectiveFormat = NULL;
712 if (readBufferHandle != 0)
713 {
714 // Not the default framebuffer, therefore the read buffer must be a user-created texture or renderbuffer
715 if (framebufferInternalFormatInfo.pixelBytes > 0)
716 {
717 sourceEffectiveFormat = &framebufferInternalFormatInfo;
718 }
719 else
720 {
721 // Renderbuffers cannot be created with an unsized internal format, so this must be an unsized-format
722 // 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 -0500723 GLenum sizedInternalFormat = GetSizedInternalFormat(framebufferInternalFormatInfo.format, framebufferInternalFormatInfo.type);
724 sourceEffectiveFormat = &GetInternalFormatInfo(sizedInternalFormat);
Geoff Lang5d601382014-07-22 15:14:06 -0400725 }
726 }
727 else
728 {
729 // The effective internal format must be derived from the source framebuffer's channel sizes.
730 // This is done in GetEffectiveInternalFormat for linear buffers (table 3.17)
731 if (framebufferInternalFormatInfo.colorEncoding == GL_LINEAR)
732 {
733 GLenum effectiveFormat;
734 if (GetEffectiveInternalFormat(framebufferInternalFormatInfo, textureInternalFormatInfo, &effectiveFormat))
735 {
736 sourceEffectiveFormat = &GetInternalFormatInfo(effectiveFormat);
737 }
738 else
739 {
740 return false;
741 }
742 }
743 else if (framebufferInternalFormatInfo.colorEncoding == GL_SRGB)
744 {
745 // SRGB buffers can only be copied to sized format destinations according to table 3.18
746 if ((textureInternalFormatInfo.pixelBytes > 0) &&
747 (framebufferInternalFormatInfo.redBits >= 1 && framebufferInternalFormatInfo.redBits <= 8) &&
748 (framebufferInternalFormatInfo.greenBits >= 1 && framebufferInternalFormatInfo.greenBits <= 8) &&
749 (framebufferInternalFormatInfo.blueBits >= 1 && framebufferInternalFormatInfo.blueBits <= 8) &&
750 (framebufferInternalFormatInfo.alphaBits >= 1 && framebufferInternalFormatInfo.alphaBits <= 8))
751 {
752 sourceEffectiveFormat = &GetInternalFormatInfo(GL_SRGB8_ALPHA8);
753 }
754 else
755 {
756 return false;
757 }
758 }
759 else
760 {
761 UNREACHABLE();
762 return false;
763 }
764 }
765
766 if (textureInternalFormatInfo.pixelBytes > 0)
767 {
768 // Section 3.8.5 of the GLES 3.0.3 spec, pg 139, requires that, if the destination format is sized,
769 // component sizes of the source and destination formats must exactly match
770 if (textureInternalFormatInfo.redBits != sourceEffectiveFormat->redBits ||
771 textureInternalFormatInfo.greenBits != sourceEffectiveFormat->greenBits ||
772 textureInternalFormatInfo.blueBits != sourceEffectiveFormat->blueBits ||
773 textureInternalFormatInfo.alphaBits != sourceEffectiveFormat->alphaBits)
774 {
775 return false;
776 }
777 }
778
779
780 return true; // A conversion function exists, and no rule in the specification has precluded conversion
781 // between these formats.
782 }
783
784 return false;
785}
786
Geoff Langb1196682014-07-23 13:47:29 -0400787bool ValidateES3CopyTexImageParameters(Context *context, GLenum target, GLint level, GLenum internalformat,
Jamie Madill6f38f822014-06-06 17:12:20 -0400788 bool isSubImage, GLint xoffset, GLint yoffset, GLint zoffset,
789 GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400790{
Jamie Madill560a8d82014-05-21 13:06:20 -0400791 GLenum textureInternalFormat;
792 if (!ValidateCopyTexImageParametersBase(context, target, level, internalformat, isSubImage,
Jamie Madill6f38f822014-06-06 17:12:20 -0400793 xoffset, yoffset, zoffset, x, y, width, height,
794 border, &textureInternalFormat))
Shannon Woods4dfed832014-03-17 20:03:39 -0400795 {
Jamie Madill560a8d82014-05-21 13:06:20 -0400796 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400797 }
798
Shannon Woods53a94a82014-06-24 15:20:36 -0400799 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -0400800
Geoff Lang748f74e2014-12-01 11:25:34 -0500801 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill3c7fa222014-06-05 13:08:51 -0400802 {
Geoff Langb1196682014-07-23 13:47:29 -0400803 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
804 return false;
Jamie Madill3c7fa222014-06-05 13:08:51 -0400805 }
806
Jamie Madill48faf802014-11-06 15:27:22 -0500807 if (context->getState().getReadFramebuffer()->id() != 0 &&
808 framebuffer->getSamples(context->getData()) != 0)
Jamie Madill3c7fa222014-06-05 13:08:51 -0400809 {
Geoff Langb1196682014-07-23 13:47:29 -0400810 context->recordError(Error(GL_INVALID_OPERATION));
811 return false;
Jamie Madill3c7fa222014-06-05 13:08:51 -0400812 }
813
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400814 const gl::FramebufferAttachment *source = framebuffer->getReadColorbuffer();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400815 GLenum colorbufferInternalFormat = source->getInternalFormat();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400816
817 if (isSubImage)
818 {
Geoff Lang5d601382014-07-22 15:14:06 -0400819 if (!IsValidES3CopyTexImageCombination(textureInternalFormat, colorbufferInternalFormat,
820 context->getState().getReadFramebuffer()->id()))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400821 {
Geoff Langb1196682014-07-23 13:47:29 -0400822 context->recordError(Error(GL_INVALID_OPERATION));
823 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400824 }
825 }
Shannon Woods4d161ba2014-03-17 18:13:30 -0400826 else
827 {
Geoff Lang5d601382014-07-22 15:14:06 -0400828 if (!gl::IsValidES3CopyTexImageCombination(internalformat, colorbufferInternalFormat,
829 context->getState().getReadFramebuffer()->id()))
Shannon Woods4d161ba2014-03-17 18:13:30 -0400830 {
Geoff Langb1196682014-07-23 13:47:29 -0400831 context->recordError(Error(GL_INVALID_OPERATION));
832 return false;
Shannon Woods4d161ba2014-03-17 18:13:30 -0400833 }
834 }
835
Geoff Lang784a8fd2013-09-24 12:33:16 -0400836 // If width or height is zero, it is a no-op. Return false without setting an error.
837 return (width > 0 && height > 0);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400838}
839
Geoff Langb1196682014-07-23 13:47:29 -0400840bool ValidateES3TexStorageParameters(Context *context, GLenum target, GLsizei levels, GLenum internalformat,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400841 GLsizei width, GLsizei height, GLsizei depth)
842{
843 if (width < 1 || height < 1 || depth < 1 || levels < 1)
844 {
Geoff Langb1196682014-07-23 13:47:29 -0400845 context->recordError(Error(GL_INVALID_VALUE));
846 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400847 }
848
Geoff Langb92c1332015-09-04 12:54:55 -0400849 GLsizei maxDim = std::max(width, height);
850 if (target != GL_TEXTURE_2D_ARRAY)
851 {
852 maxDim = std::max(maxDim, depth);
853 }
854
855 if (levels > gl::log2(maxDim) + 1)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400856 {
Geoff Langb1196682014-07-23 13:47:29 -0400857 context->recordError(Error(GL_INVALID_OPERATION));
858 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400859 }
860
Geoff Langaae65a42014-05-26 12:43:44 -0400861 const gl::Caps &caps = context->getCaps();
862
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400863 switch (target)
864 {
865 case GL_TEXTURE_2D:
866 {
Geoff Langaae65a42014-05-26 12:43:44 -0400867 if (static_cast<GLuint>(width) > caps.max2DTextureSize ||
868 static_cast<GLuint>(height) > caps.max2DTextureSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400869 {
Geoff Langb1196682014-07-23 13:47:29 -0400870 context->recordError(Error(GL_INVALID_VALUE));
871 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400872 }
873 }
874 break;
875
Geoff Lang01c21d22013-09-24 11:52:16 -0400876 case GL_TEXTURE_CUBE_MAP:
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400877 {
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400878 if (width != height)
879 {
Geoff Langb1196682014-07-23 13:47:29 -0400880 context->recordError(Error(GL_INVALID_VALUE));
881 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400882 }
883
Geoff Langaae65a42014-05-26 12:43:44 -0400884 if (static_cast<GLuint>(width) > caps.maxCubeMapTextureSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400885 {
Geoff Langb1196682014-07-23 13:47:29 -0400886 context->recordError(Error(GL_INVALID_VALUE));
887 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400888 }
889 }
890 break;
891
892 case GL_TEXTURE_3D:
893 {
Geoff Langaae65a42014-05-26 12:43:44 -0400894 if (static_cast<GLuint>(width) > caps.max3DTextureSize ||
895 static_cast<GLuint>(height) > caps.max3DTextureSize ||
896 static_cast<GLuint>(depth) > caps.max3DTextureSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400897 {
Geoff Langb1196682014-07-23 13:47:29 -0400898 context->recordError(Error(GL_INVALID_VALUE));
899 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400900 }
901 }
902 break;
903
904 case GL_TEXTURE_2D_ARRAY:
905 {
Geoff Langaae65a42014-05-26 12:43:44 -0400906 if (static_cast<GLuint>(width) > caps.max2DTextureSize ||
907 static_cast<GLuint>(height) > caps.max2DTextureSize ||
908 static_cast<GLuint>(depth) > caps.maxArrayTextureLayers)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400909 {
Geoff Langb1196682014-07-23 13:47:29 -0400910 context->recordError(Error(GL_INVALID_VALUE));
911 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400912 }
913 }
914 break;
915
916 default:
Geoff Langb1196682014-07-23 13:47:29 -0400917 context->recordError(Error(GL_INVALID_ENUM));
918 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400919 }
920
Geoff Lang691e58c2014-12-19 17:03:25 -0500921 gl::Texture *texture = context->getTargetTexture(target);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400922 if (!texture || texture->id() == 0)
923 {
Geoff Langb1196682014-07-23 13:47:29 -0400924 context->recordError(Error(GL_INVALID_OPERATION));
925 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400926 }
927
Geoff Lang69cce582015-09-17 13:20:36 -0400928 if (texture->getImmutableFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400929 {
Geoff Langb1196682014-07-23 13:47:29 -0400930 context->recordError(Error(GL_INVALID_OPERATION));
931 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400932 }
933
Geoff Lang5d601382014-07-22 15:14:06 -0400934 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
935 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400936 {
Geoff Langb1196682014-07-23 13:47:29 -0400937 context->recordError(Error(GL_INVALID_ENUM));
938 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400939 }
940
Geoff Lang5d601382014-07-22 15:14:06 -0400941 if (formatInfo.pixelBytes == 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400942 {
Geoff Langb1196682014-07-23 13:47:29 -0400943 context->recordError(Error(GL_INVALID_ENUM));
944 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400945 }
946
947 return true;
948}
949
Geoff Langb1196682014-07-23 13:47:29 -0400950bool ValidateFramebufferTextureLayer(Context *context, GLenum target, GLenum attachment,
Jamie Madill570f7c82014-07-03 10:38:54 -0400951 GLuint texture, GLint level, GLint layer)
952{
953 if (context->getClientVersion() < 3)
954 {
Geoff Langb1196682014-07-23 13:47:29 -0400955 context->recordError(Error(GL_INVALID_OPERATION));
956 return false;
Jamie Madill570f7c82014-07-03 10:38:54 -0400957 }
958
Jamie Madill55ec3b12014-07-03 10:38:57 -0400959 if (layer < 0)
960 {
Geoff Langb1196682014-07-23 13:47:29 -0400961 context->recordError(Error(GL_INVALID_VALUE));
962 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -0400963 }
964
965 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
966 {
967 return false;
968 }
969
970 const gl::Caps &caps = context->getCaps();
971 if (texture != 0)
972 {
973 gl::Texture *tex = context->getTexture(texture);
974 ASSERT(tex);
975
976 switch (tex->getTarget())
977 {
978 case GL_TEXTURE_2D_ARRAY:
979 {
980 if (level > gl::log2(caps.max2DTextureSize))
981 {
Geoff Langb1196682014-07-23 13:47:29 -0400982 context->recordError(Error(GL_INVALID_VALUE));
983 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -0400984 }
985
986 if (static_cast<GLuint>(layer) >= caps.maxArrayTextureLayers)
987 {
Geoff Langb1196682014-07-23 13:47:29 -0400988 context->recordError(Error(GL_INVALID_VALUE));
989 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -0400990 }
Jamie Madill55ec3b12014-07-03 10:38:57 -0400991 }
992 break;
993
994 case GL_TEXTURE_3D:
995 {
996 if (level > gl::log2(caps.max3DTextureSize))
997 {
Geoff Langb1196682014-07-23 13:47:29 -0400998 context->recordError(Error(GL_INVALID_VALUE));
999 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001000 }
1001
1002 if (static_cast<GLuint>(layer) >= caps.max3DTextureSize)
1003 {
Geoff Langb1196682014-07-23 13:47:29 -04001004 context->recordError(Error(GL_INVALID_VALUE));
1005 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001006 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001007 }
1008 break;
1009
1010 default:
Geoff Langb1196682014-07-23 13:47:29 -04001011 context->recordError(Error(GL_INVALID_OPERATION));
1012 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001013 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05001014
1015 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(tex->getInternalFormat(tex->getTarget(), level));
1016 if (internalFormatInfo.compressed)
1017 {
1018 context->recordError(Error(GL_INVALID_OPERATION));
1019 return false;
1020 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001021 }
1022
1023 return true;
Jamie Madill570f7c82014-07-03 10:38:54 -04001024}
1025
Geoff Langb1196682014-07-23 13:47:29 -04001026bool ValidES3ReadFormatType(Context *context, GLenum internalFormat, GLenum format, GLenum type)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001027{
Geoff Lang5d601382014-07-22 15:14:06 -04001028 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat);
1029
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001030 switch (format)
1031 {
1032 case GL_RGBA:
1033 switch (type)
1034 {
1035 case GL_UNSIGNED_BYTE:
1036 break;
1037 case GL_UNSIGNED_INT_2_10_10_10_REV:
1038 if (internalFormat != GL_RGB10_A2)
1039 {
1040 return false;
1041 }
1042 break;
Geoff Lang1ec57f82013-10-16 11:43:23 -04001043 case GL_FLOAT:
Geoff Lang5d601382014-07-22 15:14:06 -04001044 if (internalFormatInfo.componentType != GL_FLOAT)
Geoff Lang1ec57f82013-10-16 11:43:23 -04001045 {
1046 return false;
1047 }
1048 break;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001049 default:
1050 return false;
1051 }
1052 break;
1053 case GL_RGBA_INTEGER:
1054 switch (type)
1055 {
1056 case GL_INT:
Geoff Lang5d601382014-07-22 15:14:06 -04001057 if (internalFormatInfo.componentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001058 {
1059 return false;
1060 }
1061 break;
1062 case GL_UNSIGNED_INT:
Geoff Lang5d601382014-07-22 15:14:06 -04001063 if (internalFormatInfo.componentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001064 {
1065 return false;
1066 }
1067 break;
1068 default:
1069 return false;
1070 }
1071 break;
1072 case GL_BGRA_EXT:
1073 switch (type)
1074 {
1075 case GL_UNSIGNED_BYTE:
1076 case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:
1077 case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:
1078 break;
1079 default:
1080 return false;
1081 }
1082 break;
Geoff Langbdc9b2f2014-04-16 14:41:54 -04001083 case GL_RG_EXT:
1084 case GL_RED_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -04001085 if (!context->getExtensions().textureRG)
Geoff Langbdc9b2f2014-04-16 14:41:54 -04001086 {
1087 return false;
1088 }
1089 switch (type)
1090 {
1091 case GL_UNSIGNED_BYTE:
1092 break;
1093 default:
1094 return false;
1095 }
1096 break;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001097 default:
1098 return false;
1099 }
1100 return true;
1101}
1102
Corentin Walleze0902642014-11-04 12:32:15 -08001103bool ValidateES3RenderbufferStorageParameters(gl::Context *context, GLenum target, GLsizei samples,
1104 GLenum internalformat, GLsizei width, GLsizei height)
1105{
1106 if (!ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height))
1107 {
1108 return false;
1109 }
1110
1111 //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.
1112 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1113 if ((formatInfo.componentType == GL_UNSIGNED_INT || formatInfo.componentType == GL_INT) && samples > 0)
1114 {
1115 context->recordError(Error(GL_INVALID_OPERATION));
1116 return false;
1117 }
1118
1119 // The behavior is different than the ANGLE version, which would generate a GL_OUT_OF_MEMORY.
1120 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
1121 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
1122 {
1123 context->recordError(Error(GL_INVALID_VALUE));
1124 return false;
1125 }
1126
1127 return true;
1128}
1129
Austin Kinross08332632015-05-05 13:35:47 -07001130bool ValidateInvalidateFramebuffer(Context *context, GLenum target, GLsizei numAttachments,
1131 const GLenum *attachments)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001132{
Austin Kinross08332632015-05-05 13:35:47 -07001133 if (context->getClientVersion() < 3)
1134 {
1135 context->recordError(Error(GL_INVALID_OPERATION, "Operation only supported on ES 3.0 and above"));
1136 return false;
1137 }
1138
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001139 bool defaultFramebuffer = false;
1140
1141 switch (target)
1142 {
1143 case GL_DRAW_FRAMEBUFFER:
1144 case GL_FRAMEBUFFER:
Shannon Woods53a94a82014-06-24 15:20:36 -04001145 defaultFramebuffer = context->getState().getDrawFramebuffer()->id() == 0;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001146 break;
1147 case GL_READ_FRAMEBUFFER:
Shannon Woods53a94a82014-06-24 15:20:36 -04001148 defaultFramebuffer = context->getState().getReadFramebuffer()->id() == 0;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001149 break;
1150 default:
Austin Kinross08332632015-05-05 13:35:47 -07001151 context->recordError(Error(GL_INVALID_ENUM, "Invalid framebuffer target"));
1152 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001153 }
1154
Austin Kinross08332632015-05-05 13:35:47 -07001155 return ValidateDiscardFramebufferBase(context, target, numAttachments, attachments, defaultFramebuffer);
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001156}
1157
Geoff Langb1196682014-07-23 13:47:29 -04001158bool ValidateClearBuffer(Context *context)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001159{
1160 if (context->getClientVersion() < 3)
1161 {
Geoff Langb1196682014-07-23 13:47:29 -04001162 context->recordError(Error(GL_INVALID_OPERATION));
1163 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001164 }
1165
Shannon Woods53a94a82014-06-24 15:20:36 -04001166 const gl::Framebuffer *fbo = context->getState().getDrawFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001167 if (!fbo || fbo->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001168 {
Geoff Langb1196682014-07-23 13:47:29 -04001169 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1170 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001171 }
1172
1173 return true;
1174}
1175
Geoff Langb1196682014-07-23 13:47:29 -04001176bool ValidateGetUniformuiv(Context *context, GLuint program, GLint location, GLuint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001177{
1178 if (context->getClientVersion() < 3)
1179 {
Geoff Langb1196682014-07-23 13:47:29 -04001180 context->recordError(Error(GL_INVALID_OPERATION));
1181 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001182 }
1183
Jamie Madill78f41802014-08-25 15:47:55 -04001184 return ValidateGetUniformBase(context, program, location);
Jamie Madill0063c512014-08-25 15:47:53 -04001185}
1186
Jamie Madillb885e572015-02-03 16:16:04 -05001187bool ValidateReadBuffer(Context *context, GLenum src)
1188{
1189 if (context->getClientVersion() < 3)
1190 {
1191 context->recordError(Error(GL_INVALID_OPERATION));
1192 return false;
1193 }
1194
1195 Framebuffer *readFBO = context->getState().getReadFramebuffer();
1196
1197 if (readFBO == nullptr)
1198 {
1199 context->recordError(gl::Error(GL_INVALID_OPERATION, "No active read framebuffer."));
1200 return false;
1201 }
1202
1203 if (src == GL_NONE)
1204 {
1205 return true;
1206 }
1207
1208 if (src != GL_BACK && (src < GL_COLOR_ATTACHMENT0 || src > GL_COLOR_ATTACHMENT15))
1209 {
1210 context->recordError(gl::Error(GL_INVALID_ENUM, "Unknown enum for 'src' in ReadBuffer"));
1211 return false;
1212 }
1213
1214 if (readFBO->id() == 0)
1215 {
1216 if (src != GL_BACK)
1217 {
1218 const char *errorMsg = "'src' must be GL_NONE or GL_BACK when reading from the default framebuffer.";
1219 context->recordError(gl::Error(GL_INVALID_OPERATION, errorMsg));
1220 return false;
1221 }
1222 }
1223 else
1224 {
1225 GLuint drawBuffer = static_cast<GLuint>(src - GL_COLOR_ATTACHMENT0);
1226
1227 if (drawBuffer >= context->getCaps().maxDrawBuffers)
1228 {
1229 const char *errorMsg = "'src' is greater than MAX_DRAW_BUFFERS.";
1230 context->recordError(gl::Error(GL_INVALID_OPERATION, errorMsg));
1231 return false;
1232 }
1233 }
1234
1235 return true;
1236}
1237
Jamie Madill86af3d22015-07-21 15:14:07 -04001238bool ValidateCompressedTexImage3D(Context *context,
1239 GLenum target,
1240 GLint level,
1241 GLenum internalformat,
1242 GLsizei width,
1243 GLsizei height,
1244 GLsizei depth,
1245 GLint border,
1246 GLsizei imageSize,
1247 const GLvoid *data)
1248{
1249 if (context->getClientVersion() < 3)
1250 {
1251 context->recordError(Error(GL_INVALID_OPERATION));
1252 return false;
1253 }
1254
1255 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
1256 if (imageSize < 0 ||
1257 static_cast<GLuint>(imageSize) !=
1258 formatInfo.computeBlockSize(GL_UNSIGNED_BYTE, width, height))
1259 {
1260 context->recordError(Error(GL_INVALID_VALUE));
1261 return false;
1262 }
1263
1264 // 3D texture target validation
1265 if (target != GL_TEXTURE_3D && target != GL_TEXTURE_2D_ARRAY)
1266 {
1267 context->recordError(
1268 Error(GL_INVALID_ENUM, "Must specify a valid 3D texture destination target"));
1269 return false;
1270 }
1271
1272 // validateES3TexImageFormat sets the error code if there is an error
1273 if (!ValidateES3TexImageParameters(context, target, level, internalformat, true, false, 0, 0, 0,
1274 width, height, depth, border, GL_NONE, GL_NONE, data))
1275 {
1276 return false;
1277 }
1278
1279 return true;
1280}
Austin Kinrossbc781f32015-10-26 09:27:38 -07001281
1282bool ValidateBindVertexArray(Context *context, GLuint array)
1283{
1284 if (context->getClientVersion() < 3)
1285 {
1286 context->recordError(Error(GL_INVALID_OPERATION));
1287 return false;
1288 }
1289
1290 return ValidateBindVertexArrayBase(context, array);
1291}
1292
1293bool ValidateDeleteVertexArrays(Context *context, GLsizei n)
1294{
1295 if (context->getClientVersion() < 3)
1296 {
1297 context->recordError(Error(GL_INVALID_OPERATION));
1298 return false;
1299 }
1300
1301 return ValidateDeleteVertexArraysBase(context, n);
1302}
1303
1304bool ValidateGenVertexArrays(Context *context, GLsizei n)
1305{
1306 if (context->getClientVersion() < 3)
1307 {
1308 context->recordError(Error(GL_INVALID_OPERATION));
1309 return false;
1310 }
1311
1312 return ValidateGenVertexArraysBase(context, n);
1313}
1314
1315bool ValidateIsVertexArray(Context *context)
1316{
1317 if (context->getClientVersion() < 3)
1318 {
1319 context->recordError(Error(GL_INVALID_OPERATION));
1320 return false;
1321 }
1322
1323 return true;
1324}
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001325}