+
+static void
+sample_locations(struct gl_context *ctx, struct gl_framebuffer *fb,
+ GLuint start, GLsizei count, const GLfloat *v, bool no_error,
+ const char *name)
+{
+ GLsizei i;
+
+ if (!no_error) {
+ if (!ctx->Extensions.ARB_sample_locations) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s not supported "
+ "(ARB_sample_locations not available)", name);
+ return;
+ }
+
+ if (start + count > MAX_SAMPLE_LOCATION_TABLE_SIZE) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "%s(start+size > sample location table size)", name);
+ return;
+ }
+ }
+
+ if (!fb->SampleLocationTable) {
+ size_t size = MAX_SAMPLE_LOCATION_TABLE_SIZE * 2 * sizeof(GLfloat);
+ fb->SampleLocationTable = malloc(size);
+ if (!fb->SampleLocationTable) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY,
+ "Cannot allocate sample location table");
+ return;
+ }
+ for (i = 0; i < MAX_SAMPLE_LOCATION_TABLE_SIZE * 2; i++)
+ fb->SampleLocationTable[i] = 0.5f;
+ }
+
+ for (i = 0; i < count * 2; i++) {
+ /* The ARB_sample_locations spec says:
+ *
+ * Sample locations outside of [0,1] result in undefined
+ * behavior.
+ *
+ * To simplify driver implementations, we choose to clamp to
+ * [0,1] and change NaN into 0.5.
+ */
+ if (isnan(v[i]) || v[i] < 0.0f || v[i] > 1.0f) {
+ static GLuint msg_id = 0;
+ static const char* msg = "Invalid sample location specified";
+ _mesa_debug_get_id(&msg_id);
+
+ _mesa_log_msg(ctx, MESA_DEBUG_SOURCE_API, MESA_DEBUG_TYPE_UNDEFINED,
+ msg_id, MESA_DEBUG_SEVERITY_HIGH, strlen(msg), msg);
+ }
+
+ if (isnan(v[i]))
+ fb->SampleLocationTable[start * 2 + i] = 0.5f;
+ else
+ fb->SampleLocationTable[start * 2 + i] = CLAMP(v[i], 0.0f, 1.0f);
+ }
+
+ if (fb == ctx->DrawBuffer)
+ ctx->NewDriverState |= ctx->DriverFlags.NewSampleLocations;
+}
+
+void GLAPIENTRY
+_mesa_FramebufferSampleLocationsfvARB(GLenum target, GLuint start,
+ GLsizei count, const GLfloat *v)
+{
+ struct gl_framebuffer *fb;
+
+ GET_CURRENT_CONTEXT(ctx);
+
+ fb = get_framebuffer_target(ctx, target);
+ if (!fb) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glFramebufferSampleLocationsfvARB(target %s)",
+ _mesa_enum_to_string(target));
+ return;
+ }
+
+ sample_locations(ctx, fb, start, count, v, false,
+ "glFramebufferSampleLocationsfvARB");
+}
+
+void GLAPIENTRY
+_mesa_NamedFramebufferSampleLocationsfvARB(GLuint framebuffer, GLuint start,
+ GLsizei count, const GLfloat *v)
+{
+ struct gl_framebuffer *fb;
+
+ GET_CURRENT_CONTEXT(ctx);
+
+ if (framebuffer) {
+ fb = _mesa_lookup_framebuffer_err(ctx, framebuffer,
+ "glNamedFramebufferSampleLocationsfvARB");
+ if (!fb)
+ return;
+ }
+ else
+ fb = ctx->WinSysDrawBuffer;
+
+ sample_locations(ctx, fb, start, count, v, false,
+ "glNamedFramebufferSampleLocationsfvARB");
+}
+
+void GLAPIENTRY
+_mesa_FramebufferSampleLocationsfvARB_no_error(GLenum target, GLuint start,
+ GLsizei count, const GLfloat *v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ sample_locations(ctx, get_framebuffer_target(ctx, target), start,
+ count, v, true, "glFramebufferSampleLocationsfvARB");
+}
+
+void GLAPIENTRY
+_mesa_NamedFramebufferSampleLocationsfvARB_no_error(GLuint framebuffer,
+ GLuint start, GLsizei count,
+ const GLfloat *v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ sample_locations(ctx, _mesa_lookup_framebuffer(ctx, framebuffer), start,
+ count, v, true, "glNamedFramebufferSampleLocationsfvARB");
+}
+
+void GLAPIENTRY
+_mesa_EvaluateDepthValuesARB(void)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ if (!ctx->Extensions.ARB_sample_locations) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "EvaluateDepthValuesARB not supported (neither "
+ "ARB_sample_locations nor NV_sample_locations is available)");
+ return;
+ }
+
+ if (ctx->Driver.EvaluateDepthValues)
+ ctx->Driver.EvaluateDepthValues(ctx);
+}