1 /*
2  * Mesa 3-D graphics library
3  *
4  * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included
14  * in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22  * OTHER DEALINGS IN THE SOFTWARE.
23  */
24 
25 
26 #include "main/glheader.h"
27 #include "main/context.h"
28 #include "main/macros.h"
29 #include "main/multisample.h"
30 #include "main/mtypes.h"
31 #include "main/fbobject.h"
32 #include "main/glformats.h"
33 #include "main/state.h"
34 
35 
36 /**
37  * Called via glSampleCoverageARB
38  */
39 void GLAPIENTRY
_mesa_SampleCoverage(GLclampf value,GLboolean invert)40 _mesa_SampleCoverage(GLclampf value, GLboolean invert)
41 {
42    GET_CURRENT_CONTEXT(ctx);
43 
44    value = SATURATE(value);
45 
46    if (ctx->Multisample.SampleCoverageInvert == invert &&
47        ctx->Multisample.SampleCoverageValue == value)
48       return;
49 
50    FLUSH_VERTICES(ctx, ctx->DriverFlags.NewSampleMask ? 0 : _NEW_MULTISAMPLE);
51    ctx->NewDriverState |= ctx->DriverFlags.NewSampleMask;
52    ctx->Multisample.SampleCoverageValue = value;
53    ctx->Multisample.SampleCoverageInvert = invert;
54 }
55 
56 
57 /**
58  * Initialize the context's multisample state.
59  * \param ctx  the GL context.
60  */
61 void
_mesa_init_multisample(struct gl_context * ctx)62 _mesa_init_multisample(struct gl_context *ctx)
63 {
64    ctx->Multisample.Enabled = GL_TRUE;
65    ctx->Multisample.SampleAlphaToCoverage = GL_FALSE;
66    ctx->Multisample.SampleAlphaToCoverageDitherControl = GL_ALPHA_TO_COVERAGE_DITHER_DEFAULT_NV;
67    ctx->Multisample.SampleAlphaToOne = GL_FALSE;
68    ctx->Multisample.SampleCoverage = GL_FALSE;
69    ctx->Multisample.SampleCoverageValue = 1.0;
70    ctx->Multisample.SampleCoverageInvert = GL_FALSE;
71    ctx->Multisample.SampleShading = GL_FALSE;
72    ctx->Multisample.MinSampleShadingValue = 0.0f;
73 
74    /* ARB_texture_multisample / GL3.2 additions */
75    ctx->Multisample.SampleMask = GL_FALSE;
76    ctx->Multisample.SampleMaskValue = ~(GLbitfield)0;
77 }
78 
79 
80 void GLAPIENTRY
_mesa_GetMultisamplefv(GLenum pname,GLuint index,GLfloat * val)81 _mesa_GetMultisamplefv(GLenum pname, GLuint index, GLfloat * val)
82 {
83    GET_CURRENT_CONTEXT(ctx);
84 
85    if (ctx->NewState & _NEW_BUFFERS) {
86       _mesa_update_state(ctx);
87    }
88 
89    switch (pname) {
90    case GL_SAMPLE_POSITION: {
91       if (index >= ctx->DrawBuffer->Visual.samples) {
92          _mesa_error( ctx, GL_INVALID_VALUE, "glGetMultisamplefv(index)" );
93          return;
94       }
95 
96       ctx->Driver.GetSamplePosition(ctx, ctx->DrawBuffer, index, val);
97 
98       /* FBOs can be upside down (winsys always are)*/
99       if (ctx->DrawBuffer->FlipY)
100          val[1] = 1.0f - val[1];
101 
102       return;
103    }
104 
105    case GL_PROGRAMMABLE_SAMPLE_LOCATION_ARB:
106       if (!ctx->Extensions.ARB_sample_locations) {
107          _mesa_error( ctx, GL_INVALID_ENUM, "glGetMultisamplefv(pname)" );
108          return;
109       }
110 
111       if (index >= MAX_SAMPLE_LOCATION_TABLE_SIZE * 2) {
112          _mesa_error( ctx, GL_INVALID_VALUE, "glGetMultisamplefv(index)" );
113          return;
114       }
115 
116       if (ctx->DrawBuffer->SampleLocationTable)
117          *val = ctx->DrawBuffer->SampleLocationTable[index];
118       else
119          *val = 0.5f;
120 
121       return;
122 
123    default:
124       _mesa_error( ctx, GL_INVALID_ENUM, "glGetMultisamplefv(pname)" );
125       return;
126    }
127 }
128 
129 static void
sample_maski(struct gl_context * ctx,GLuint index,GLbitfield mask)130 sample_maski(struct gl_context *ctx, GLuint index, GLbitfield mask)
131 {
132    if (ctx->Multisample.SampleMaskValue == mask)
133       return;
134 
135    FLUSH_VERTICES(ctx, ctx->DriverFlags.NewSampleMask ? 0 : _NEW_MULTISAMPLE);
136    ctx->NewDriverState |= ctx->DriverFlags.NewSampleMask;
137    ctx->Multisample.SampleMaskValue = mask;
138 }
139 
140 void GLAPIENTRY
_mesa_SampleMaski_no_error(GLuint index,GLbitfield mask)141 _mesa_SampleMaski_no_error(GLuint index, GLbitfield mask)
142 {
143    GET_CURRENT_CONTEXT(ctx);
144    sample_maski(ctx, index, mask);
145 }
146 
147 void GLAPIENTRY
_mesa_SampleMaski(GLuint index,GLbitfield mask)148 _mesa_SampleMaski(GLuint index, GLbitfield mask)
149 {
150    GET_CURRENT_CONTEXT(ctx);
151 
152    if (!ctx->Extensions.ARB_texture_multisample) {
153       _mesa_error(ctx, GL_INVALID_OPERATION, "glSampleMaski");
154       return;
155    }
156 
157    if (index != 0) {
158       _mesa_error(ctx, GL_INVALID_VALUE, "glSampleMaski(index)");
159       return;
160    }
161 
162    sample_maski(ctx, index, mask);
163 }
164 
165 static void
min_sample_shading(struct gl_context * ctx,GLclampf value)166 min_sample_shading(struct gl_context *ctx, GLclampf value)
167 {
168    value = SATURATE(value);
169 
170    if (ctx->Multisample.MinSampleShadingValue == value)
171       return;
172 
173    FLUSH_VERTICES(ctx,
174                   ctx->DriverFlags.NewSampleShading ? 0 : _NEW_MULTISAMPLE);
175    ctx->NewDriverState |= ctx->DriverFlags.NewSampleShading;
176    ctx->Multisample.MinSampleShadingValue = value;
177 }
178 
179 /**
180  * Called via glMinSampleShadingARB
181  */
182 void GLAPIENTRY
_mesa_MinSampleShading_no_error(GLclampf value)183 _mesa_MinSampleShading_no_error(GLclampf value)
184 {
185    GET_CURRENT_CONTEXT(ctx);
186    min_sample_shading(ctx, value);
187 }
188 
189 void GLAPIENTRY
_mesa_MinSampleShading(GLclampf value)190 _mesa_MinSampleShading(GLclampf value)
191 {
192    GET_CURRENT_CONTEXT(ctx);
193 
194    if (!_mesa_has_ARB_sample_shading(ctx) &&
195        !_mesa_has_OES_sample_shading(ctx)) {
196       _mesa_error(ctx, GL_INVALID_OPERATION, "glMinSampleShading");
197       return;
198    }
199 
200    min_sample_shading(ctx, value);
201 }
202 
203 /**
204  * Helper for checking a requested sample count against the limit
205  * for a particular (target, internalFormat) pair. The limit imposed,
206  * and the error generated, both depend on which extensions are supported.
207  *
208  * Returns a GL error enum, or GL_NO_ERROR if the requested sample count is
209  * acceptable.
210  */
211 GLenum
_mesa_check_sample_count(struct gl_context * ctx,GLenum target,GLenum internalFormat,GLsizei samples,GLsizei storageSamples)212 _mesa_check_sample_count(struct gl_context *ctx, GLenum target,
213                          GLenum internalFormat, GLsizei samples,
214                          GLsizei storageSamples)
215 {
216    /* Section 4.4 (Framebuffer objects), page 198 of the OpenGL ES 3.0.0
217     * specification says:
218     *
219     *     "If internalformat is a signed or unsigned integer format and samples
220     *     is greater than zero, then the error INVALID_OPERATION is generated."
221     *
222     * This restriction is relaxed for OpenGL ES 3.1.
223     */
224    if ((ctx->API == API_OPENGLES2 && ctx->Version == 30) &&
225        _mesa_is_enum_format_integer(internalFormat)
226        && samples > 0) {
227       return GL_INVALID_OPERATION;
228    }
229 
230    if (ctx->Extensions.AMD_framebuffer_multisample_advanced &&
231        target == GL_RENDERBUFFER) {
232       if (!_mesa_is_depth_or_stencil_format(internalFormat)) {
233          /* From the AMD_framebuffer_multisample_advanced spec:
234           *
235           *    "An INVALID_OPERATION error is generated if <internalformat>
236           *     is a color format and <storageSamples> is greater than
237           *     the implementation-dependent limit MAX_COLOR_FRAMEBUFFER_-
238           *     STORAGE_SAMPLES_AMD."
239           */
240          if (samples > ctx->Const.MaxColorFramebufferSamples)
241             return GL_INVALID_OPERATION;
242 
243          /* From the AMD_framebuffer_multisample_advanced spec:
244           *
245           *    "An INVALID_OPERATION error is generated if <internalformat>
246           *     is a color format and <storageSamples> is greater than
247           *     the implementation-dependent limit MAX_COLOR_FRAMEBUFFER_-
248           *     STORAGE_SAMPLES_AMD."
249           */
250          if (storageSamples > ctx->Const.MaxColorFramebufferStorageSamples)
251             return GL_INVALID_OPERATION;
252 
253          /* From the AMD_framebuffer_multisample_advanced spec:
254           *
255           *    "An INVALID_OPERATION error is generated if <storageSamples> is
256           *     greater than <samples>."
257           */
258          if (storageSamples > samples)
259             return GL_INVALID_OPERATION;
260 
261          /* Color renderbuffer sample counts are now fully validated
262           * according to AMD_framebuffer_multisample_advanced.
263           */
264          return GL_NO_ERROR;
265       } else {
266          /* From the AMD_framebuffer_multisample_advanced spec:
267           *
268           *    "An INVALID_OPERATION error is generated if <internalformat> is
269           *     a depth or stencil format and <storageSamples> is not equal to
270           *     <samples>."
271           */
272          if (storageSamples != samples)
273             return GL_INVALID_OPERATION;
274       }
275    } else {
276       /* If the extension is unsupported, it's not possible to set
277        * storageSamples differently.
278        */
279       assert(samples == storageSamples);
280    }
281 
282    /* If ARB_internalformat_query is supported, then treat its highest
283     * returned sample count as the absolute maximum for this format; it is
284     * allowed to exceed MAX_SAMPLES.
285     *
286     * From the ARB_internalformat_query spec:
287     *
288     * "If <samples is greater than the maximum number of samples supported
289     * for <internalformat> then the error INVALID_OPERATION is generated."
290     */
291    if (ctx->Extensions.ARB_internalformat_query) {
292       GLint buffer[16] = {-1};
293       GLint limit;
294 
295       ctx->Driver.QueryInternalFormat(ctx, target, internalFormat,
296                                       GL_SAMPLES, buffer);
297       /* since the query returns samples sorted in descending order,
298        * the first element is the greatest supported sample value.
299        */
300       limit = buffer[0];
301 
302       return samples > limit ? GL_INVALID_OPERATION : GL_NO_ERROR;
303    }
304 
305    /* If ARB_texture_multisample is supported, we have separate limits,
306     * which may be lower than MAX_SAMPLES:
307     *
308     * From the ARB_texture_multisample spec, when describing the operation
309     * of RenderbufferStorageMultisample:
310     *
311     * "If <internalformat> is a signed or unsigned integer format and
312     * <samples> is greater than the value of MAX_INTEGER_SAMPLES, then the
313     * error INVALID_OPERATION is generated"
314     *
315     * And when describing the operation of TexImage*Multisample:
316     *
317     * "The error INVALID_OPERATION may be generated if any of the following
318     * are true:
319     *
320     * * <internalformat> is a depth/stencil-renderable format and <samples>
321     *   is greater than the value of MAX_DEPTH_TEXTURE_SAMPLES
322     * * <internalformat> is a color-renderable format and <samples> is
323     *   grater than the value of MAX_COLOR_TEXTURE_SAMPLES
324     * * <internalformat> is a signed or unsigned integer format and
325     *   <samples> is greater than the value of MAX_INTEGER_SAMPLES
326     */
327 
328    if (ctx->Extensions.ARB_texture_multisample) {
329       if (_mesa_is_enum_format_integer(internalFormat))
330          return samples > ctx->Const.MaxIntegerSamples
331             ? GL_INVALID_OPERATION : GL_NO_ERROR;
332 
333       if (target == GL_TEXTURE_2D_MULTISAMPLE ||
334           target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) {
335 
336          if (_mesa_is_depth_or_stencil_format(internalFormat))
337             return samples > ctx->Const.MaxDepthTextureSamples
338                ? GL_INVALID_OPERATION : GL_NO_ERROR;
339          else
340             return samples > ctx->Const.MaxColorTextureSamples
341                ? GL_INVALID_OPERATION : GL_NO_ERROR;
342       }
343    }
344 
345    /* No more specific limit is available, so just use MAX_SAMPLES:
346     *
347     * On p205 of the GL3.1 spec:
348     *
349     * "... or if samples is greater than MAX_SAMPLES, then the error
350     * INVALID_VALUE is generated"
351     */
352    return (GLuint) samples > ctx->Const.MaxSamples
353       ? GL_INVALID_VALUE : GL_NO_ERROR;
354 }
355 
356 void GLAPIENTRY
_mesa_AlphaToCoverageDitherControlNV_no_error(GLenum mode)357 _mesa_AlphaToCoverageDitherControlNV_no_error(GLenum mode)
358 {
359    GET_CURRENT_CONTEXT(ctx);
360 
361    FLUSH_VERTICES(ctx, ctx->DriverFlags.NewSampleAlphaToXEnable ? 0 :
362                                                    _NEW_MULTISAMPLE);
363    ctx->NewDriverState |= ctx->DriverFlags.NewSampleAlphaToXEnable;
364    ctx->Multisample.SampleAlphaToCoverageDitherControl = mode;
365 }
366 
367 void GLAPIENTRY
_mesa_AlphaToCoverageDitherControlNV(GLenum mode)368 _mesa_AlphaToCoverageDitherControlNV(GLenum mode)
369 {
370    GET_CURRENT_CONTEXT(ctx);
371 
372    FLUSH_VERTICES(ctx, ctx->DriverFlags.NewSampleAlphaToXEnable ? 0 :
373                                                    _NEW_MULTISAMPLE);
374    ctx->NewDriverState |= ctx->DriverFlags.NewSampleAlphaToXEnable;
375    switch (mode) {
376       case GL_ALPHA_TO_COVERAGE_DITHER_DEFAULT_NV:
377       case GL_ALPHA_TO_COVERAGE_DITHER_ENABLE_NV:
378       case GL_ALPHA_TO_COVERAGE_DITHER_DISABLE_NV:
379          ctx->Multisample.SampleAlphaToCoverageDitherControl = mode;
380          break;
381       default:
382          _mesa_error(ctx, GL_INVALID_ENUM, "glAlphaToCoverageDitherControlNV(invalid parameter)");
383    }
384 }
385