multisample.c revision 7ec681f3
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 */ 39void GLAPIENTRY 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 GL_MULTISAMPLE_BIT); 52 ctx->NewDriverState |= ctx->DriverFlags.NewSampleMask; 53 ctx->Multisample.SampleCoverageValue = value; 54 ctx->Multisample.SampleCoverageInvert = invert; 55} 56 57 58/** 59 * Initialize the context's multisample state. 60 * \param ctx the GL context. 61 */ 62void 63_mesa_init_multisample(struct gl_context *ctx) 64{ 65 ctx->Multisample.Enabled = GL_TRUE; 66 ctx->Multisample.SampleAlphaToCoverage = GL_FALSE; 67 ctx->Multisample.SampleAlphaToCoverageDitherControl = GL_ALPHA_TO_COVERAGE_DITHER_DEFAULT_NV; 68 ctx->Multisample.SampleAlphaToOne = GL_FALSE; 69 ctx->Multisample.SampleCoverage = GL_FALSE; 70 ctx->Multisample.SampleCoverageValue = 1.0; 71 ctx->Multisample.SampleCoverageInvert = GL_FALSE; 72 ctx->Multisample.SampleShading = GL_FALSE; 73 ctx->Multisample.MinSampleShadingValue = 0.0f; 74 75 /* ARB_texture_multisample / GL3.2 additions */ 76 ctx->Multisample.SampleMask = GL_FALSE; 77 ctx->Multisample.SampleMaskValue = ~(GLbitfield)0; 78} 79 80 81void GLAPIENTRY 82_mesa_GetMultisamplefv(GLenum pname, GLuint index, GLfloat * val) 83{ 84 GET_CURRENT_CONTEXT(ctx); 85 86 if (ctx->NewState & _NEW_BUFFERS) { 87 _mesa_update_state(ctx); 88 } 89 90 switch (pname) { 91 case GL_SAMPLE_POSITION: { 92 if (index >= ctx->DrawBuffer->Visual.samples) { 93 _mesa_error( ctx, GL_INVALID_VALUE, "glGetMultisamplefv(index)" ); 94 return; 95 } 96 97 ctx->Driver.GetSamplePosition(ctx, ctx->DrawBuffer, index, val); 98 99 /* FBOs can be upside down (winsys always are)*/ 100 if (ctx->DrawBuffer->FlipY) 101 val[1] = 1.0f - val[1]; 102 103 return; 104 } 105 106 case GL_PROGRAMMABLE_SAMPLE_LOCATION_ARB: 107 if (!ctx->Extensions.ARB_sample_locations) { 108 _mesa_error( ctx, GL_INVALID_ENUM, "glGetMultisamplefv(pname)" ); 109 return; 110 } 111 112 if (index >= MAX_SAMPLE_LOCATION_TABLE_SIZE * 2) { 113 _mesa_error( ctx, GL_INVALID_VALUE, "glGetMultisamplefv(index)" ); 114 return; 115 } 116 117 if (ctx->DrawBuffer->SampleLocationTable) 118 *val = ctx->DrawBuffer->SampleLocationTable[index]; 119 else 120 *val = 0.5f; 121 122 return; 123 124 default: 125 _mesa_error( ctx, GL_INVALID_ENUM, "glGetMultisamplefv(pname)" ); 126 return; 127 } 128} 129 130static void 131sample_maski(struct gl_context *ctx, GLuint index, GLbitfield mask) 132{ 133 if (ctx->Multisample.SampleMaskValue == mask) 134 return; 135 136 FLUSH_VERTICES(ctx, ctx->DriverFlags.NewSampleMask ? 0 : _NEW_MULTISAMPLE, 0); 137 ctx->NewDriverState |= ctx->DriverFlags.NewSampleMask; 138 ctx->Multisample.SampleMaskValue = mask; 139} 140 141void GLAPIENTRY 142_mesa_SampleMaski_no_error(GLuint index, GLbitfield mask) 143{ 144 GET_CURRENT_CONTEXT(ctx); 145 sample_maski(ctx, index, mask); 146} 147 148void GLAPIENTRY 149_mesa_SampleMaski(GLuint index, GLbitfield mask) 150{ 151 GET_CURRENT_CONTEXT(ctx); 152 153 if (!ctx->Extensions.ARB_texture_multisample) { 154 _mesa_error(ctx, GL_INVALID_OPERATION, "glSampleMaski"); 155 return; 156 } 157 158 if (index != 0) { 159 _mesa_error(ctx, GL_INVALID_VALUE, "glSampleMaski(index)"); 160 return; 161 } 162 163 sample_maski(ctx, index, mask); 164} 165 166static void 167min_sample_shading(struct gl_context *ctx, GLclampf value) 168{ 169 value = SATURATE(value); 170 171 if (ctx->Multisample.MinSampleShadingValue == value) 172 return; 173 174 FLUSH_VERTICES(ctx, 175 ctx->DriverFlags.NewSampleShading ? 0 : _NEW_MULTISAMPLE, 176 GL_MULTISAMPLE_BIT); 177 ctx->NewDriverState |= ctx->DriverFlags.NewSampleShading; 178 ctx->Multisample.MinSampleShadingValue = value; 179} 180 181/** 182 * Called via glMinSampleShadingARB 183 */ 184void GLAPIENTRY 185_mesa_MinSampleShading_no_error(GLclampf value) 186{ 187 GET_CURRENT_CONTEXT(ctx); 188 min_sample_shading(ctx, value); 189} 190 191void GLAPIENTRY 192_mesa_MinSampleShading(GLclampf value) 193{ 194 GET_CURRENT_CONTEXT(ctx); 195 196 if (!_mesa_has_ARB_sample_shading(ctx) && 197 !_mesa_has_OES_sample_shading(ctx)) { 198 _mesa_error(ctx, GL_INVALID_OPERATION, "glMinSampleShading"); 199 return; 200 } 201 202 min_sample_shading(ctx, value); 203} 204 205/** 206 * Helper for checking a requested sample count against the limit 207 * for a particular (target, internalFormat) pair. The limit imposed, 208 * and the error generated, both depend on which extensions are supported. 209 * 210 * Returns a GL error enum, or GL_NO_ERROR if the requested sample count is 211 * acceptable. 212 */ 213GLenum 214_mesa_check_sample_count(struct gl_context *ctx, GLenum target, 215 GLenum internalFormat, GLsizei samples, 216 GLsizei storageSamples) 217{ 218 /* Section 4.4 (Framebuffer objects), page 198 of the OpenGL ES 3.0.0 219 * specification says: 220 * 221 * "If internalformat is a signed or unsigned integer format and samples 222 * is greater than zero, then the error INVALID_OPERATION is generated." 223 * 224 * This restriction is relaxed for OpenGL ES 3.1. 225 */ 226 if ((ctx->API == API_OPENGLES2 && ctx->Version == 30) && 227 _mesa_is_enum_format_integer(internalFormat) 228 && samples > 0) { 229 return GL_INVALID_OPERATION; 230 } 231 232 if (ctx->Extensions.AMD_framebuffer_multisample_advanced && 233 target == GL_RENDERBUFFER) { 234 if (!_mesa_is_depth_or_stencil_format(internalFormat)) { 235 /* From the AMD_framebuffer_multisample_advanced spec: 236 * 237 * "An INVALID_OPERATION error is generated if <internalformat> 238 * is a color format and <storageSamples> is greater than 239 * the implementation-dependent limit MAX_COLOR_FRAMEBUFFER_- 240 * STORAGE_SAMPLES_AMD." 241 */ 242 if (samples > ctx->Const.MaxColorFramebufferSamples) 243 return GL_INVALID_OPERATION; 244 245 /* From the AMD_framebuffer_multisample_advanced spec: 246 * 247 * "An INVALID_OPERATION error is generated if <internalformat> 248 * is a color format and <storageSamples> is greater than 249 * the implementation-dependent limit MAX_COLOR_FRAMEBUFFER_- 250 * STORAGE_SAMPLES_AMD." 251 */ 252 if (storageSamples > ctx->Const.MaxColorFramebufferStorageSamples) 253 return GL_INVALID_OPERATION; 254 255 /* From the AMD_framebuffer_multisample_advanced spec: 256 * 257 * "An INVALID_OPERATION error is generated if <storageSamples> is 258 * greater than <samples>." 259 */ 260 if (storageSamples > samples) 261 return GL_INVALID_OPERATION; 262 263 /* Color renderbuffer sample counts are now fully validated 264 * according to AMD_framebuffer_multisample_advanced. 265 */ 266 return GL_NO_ERROR; 267 } else { 268 /* From the AMD_framebuffer_multisample_advanced spec: 269 * 270 * "An INVALID_OPERATION error is generated if <internalformat> is 271 * a depth or stencil format and <storageSamples> is not equal to 272 * <samples>." 273 */ 274 if (storageSamples != samples) 275 return GL_INVALID_OPERATION; 276 } 277 } else { 278 /* If the extension is unsupported, it's not possible to set 279 * storageSamples differently. 280 */ 281 assert(samples == storageSamples); 282 } 283 284 /* If ARB_internalformat_query is supported, then treat its highest 285 * returned sample count as the absolute maximum for this format; it is 286 * allowed to exceed MAX_SAMPLES. 287 * 288 * From the ARB_internalformat_query spec: 289 * 290 * "If <samples is greater than the maximum number of samples supported 291 * for <internalformat> then the error INVALID_OPERATION is generated." 292 */ 293 if (ctx->Extensions.ARB_internalformat_query) { 294 GLint buffer[16] = {-1}; 295 GLint limit; 296 297 ctx->Driver.QueryInternalFormat(ctx, target, internalFormat, 298 GL_SAMPLES, buffer); 299 /* since the query returns samples sorted in descending order, 300 * the first element is the greatest supported sample value. 301 */ 302 limit = buffer[0]; 303 304 return samples > limit ? GL_INVALID_OPERATION : GL_NO_ERROR; 305 } 306 307 /* If ARB_texture_multisample is supported, we have separate limits, 308 * which may be lower than MAX_SAMPLES: 309 * 310 * From the ARB_texture_multisample spec, when describing the operation 311 * of RenderbufferStorageMultisample: 312 * 313 * "If <internalformat> is a signed or unsigned integer format and 314 * <samples> is greater than the value of MAX_INTEGER_SAMPLES, then the 315 * error INVALID_OPERATION is generated" 316 * 317 * And when describing the operation of TexImage*Multisample: 318 * 319 * "The error INVALID_OPERATION may be generated if any of the following 320 * are true: 321 * 322 * * <internalformat> is a depth/stencil-renderable format and <samples> 323 * is greater than the value of MAX_DEPTH_TEXTURE_SAMPLES 324 * * <internalformat> is a color-renderable format and <samples> is 325 * grater than the value of MAX_COLOR_TEXTURE_SAMPLES 326 * * <internalformat> is a signed or unsigned integer format and 327 * <samples> is greater than the value of MAX_INTEGER_SAMPLES 328 */ 329 330 if (ctx->Extensions.ARB_texture_multisample) { 331 if (_mesa_is_enum_format_integer(internalFormat)) 332 return samples > ctx->Const.MaxIntegerSamples 333 ? GL_INVALID_OPERATION : GL_NO_ERROR; 334 335 if (target == GL_TEXTURE_2D_MULTISAMPLE || 336 target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) { 337 338 if (_mesa_is_depth_or_stencil_format(internalFormat)) 339 return samples > ctx->Const.MaxDepthTextureSamples 340 ? GL_INVALID_OPERATION : GL_NO_ERROR; 341 else 342 return samples > ctx->Const.MaxColorTextureSamples 343 ? GL_INVALID_OPERATION : GL_NO_ERROR; 344 } 345 } 346 347 /* No more specific limit is available, so just use MAX_SAMPLES: 348 * 349 * On p205 of the GL3.1 spec: 350 * 351 * "... or if samples is greater than MAX_SAMPLES, then the error 352 * INVALID_VALUE is generated" 353 */ 354 return (GLuint) samples > ctx->Const.MaxSamples 355 ? GL_INVALID_VALUE : GL_NO_ERROR; 356} 357 358void GLAPIENTRY 359_mesa_AlphaToCoverageDitherControlNV_no_error(GLenum mode) 360{ 361 GET_CURRENT_CONTEXT(ctx); 362 363 FLUSH_VERTICES(ctx, ctx->DriverFlags.NewSampleAlphaToXEnable ? 0 : 364 _NEW_MULTISAMPLE, 365 GL_MULTISAMPLE_BIT); 366 ctx->NewDriverState |= ctx->DriverFlags.NewSampleAlphaToXEnable; 367 ctx->Multisample.SampleAlphaToCoverageDitherControl = mode; 368} 369 370void GLAPIENTRY 371_mesa_AlphaToCoverageDitherControlNV(GLenum mode) 372{ 373 GET_CURRENT_CONTEXT(ctx); 374 375 FLUSH_VERTICES(ctx, ctx->DriverFlags.NewSampleAlphaToXEnable ? 0 : 376 _NEW_MULTISAMPLE, 377 GL_MULTISAMPLE_BIT); 378 ctx->NewDriverState |= ctx->DriverFlags.NewSampleAlphaToXEnable; 379 switch (mode) { 380 case GL_ALPHA_TO_COVERAGE_DITHER_DEFAULT_NV: 381 case GL_ALPHA_TO_COVERAGE_DITHER_ENABLE_NV: 382 case GL_ALPHA_TO_COVERAGE_DITHER_DISABLE_NV: 383 ctx->Multisample.SampleAlphaToCoverageDitherControl = mode; 384 break; 385 default: 386 _mesa_error(ctx, GL_INVALID_ENUM, "glAlphaToCoverageDitherControlNV(invalid parameter)"); 387 } 388} 389