* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
- * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
*/
#include "main/glheader.h"
#include "main/context.h"
-#include "main/dispatch.h"
#include "main/enums.h"
#include "main/hash.h"
#include "main/macros.h"
-#include "main/mfeatures.h"
#include "main/mtypes.h"
#include "main/samplerobj.h"
+#include "main/texturebindless.h"
-static struct gl_sampler_object *
+struct gl_sampler_object *
_mesa_lookup_samplerobj(struct gl_context *ctx, GLuint name)
{
if (name == 0)
_mesa_HashLookup(ctx->Shared->SamplerObjects, name);
}
+static inline struct gl_sampler_object *
+lookup_samplerobj_locked(struct gl_context *ctx, GLuint name)
+{
+ return (struct gl_sampler_object *)
+ _mesa_HashLookupLocked(ctx->Shared->SamplerObjects, name);
+}
+
+static void
+delete_sampler_object(struct gl_context *ctx,
+ struct gl_sampler_object *sampObj)
+{
+ _mesa_delete_sampler_handles(ctx, sampObj);
+ simple_mtx_destroy(&sampObj->Mutex);
+ free(sampObj->Label);
+ free(sampObj);
+}
/**
* Handle reference counting.
*/
void
-_mesa_reference_sampler_object(struct gl_context *ctx,
- struct gl_sampler_object **ptr,
- struct gl_sampler_object *samp)
+_mesa_reference_sampler_object_(struct gl_context *ctx,
+ struct gl_sampler_object **ptr,
+ struct gl_sampler_object *samp)
{
- if (*ptr == samp)
- return;
+ assert(*ptr != samp); /* The inline wrapper should prevent no-op calls */
if (*ptr) {
/* Unreference the old sampler */
GLboolean deleteFlag = GL_FALSE;
struct gl_sampler_object *oldSamp = *ptr;
- /*_glthread_LOCK_MUTEX(oldSamp->Mutex);*/
- ASSERT(oldSamp->RefCount > 0);
+ simple_mtx_lock(&oldSamp->Mutex);
+ assert(oldSamp->RefCount > 0);
oldSamp->RefCount--;
-#if 0
- printf("SamplerObj %p %d DECR to %d\n",
- (void *) oldSamp, oldSamp->Name, oldSamp->RefCount);
-#endif
deleteFlag = (oldSamp->RefCount == 0);
- /*_glthread_UNLOCK_MUTEX(oldSamp->Mutex);*/
+ simple_mtx_unlock(&oldSamp->Mutex);
- if (deleteFlag) {
- ASSERT(ctx->Driver.DeleteSamplerObject);
- ctx->Driver.DeleteSamplerObject(ctx, oldSamp);
- }
+ if (deleteFlag)
+ delete_sampler_object(ctx, oldSamp);
*ptr = NULL;
}
- ASSERT(!*ptr);
+ assert(!*ptr);
if (samp) {
/* reference new sampler */
- /*_glthread_LOCK_MUTEX(samp->Mutex);*/
- if (samp->RefCount == 0) {
- /* this sampler's being deleted (look just above) */
- /* Not sure this can every really happen. Warn if it does. */
- _mesa_problem(NULL, "referencing deleted sampler object");
- *ptr = NULL;
- }
- else {
- samp->RefCount++;
-#if 0
- printf("SamplerObj %p %d INCR to %d\n",
- (void *) samp, samp->Name, samp->RefCount);
-#endif
- *ptr = samp;
- }
- /*_glthread_UNLOCK_MUTEX(samp->Mutex);*/
+ simple_mtx_lock(&samp->Mutex);
+ assert(samp->RefCount > 0);
+
+ samp->RefCount++;
+ *ptr = samp;
+ simple_mtx_unlock(&samp->Mutex);
}
}
/**
* Initialize the fields of the given sampler object.
*/
-void
+static void
_mesa_init_sampler_object(struct gl_sampler_object *sampObj, GLuint name)
{
+ simple_mtx_init(&sampObj->Mutex, mtx_plain);
sampObj->Name = name;
sampObj->RefCount = 1;
sampObj->WrapS = GL_REPEAT;
sampObj->MaxAnisotropy = 1.0F;
sampObj->CompareMode = GL_NONE;
sampObj->CompareFunc = GL_LEQUAL;
- sampObj->CompareFailValue = 0.0;
- sampObj->sRGBDecode = GL_FALSE;
- sampObj->DepthMode = 0;
-}
+ sampObj->sRGBDecode = GL_DECODE_EXT;
+ sampObj->CubeMapSeamless = GL_FALSE;
+ sampObj->HandleAllocated = GL_FALSE;
+ /* GL_ARB_bindless_texture */
+ _mesa_init_sampler_handles(sampObj);
+}
/**
* Fallback for ctx->Driver.NewSamplerObject();
return sampObj;
}
-
-/**
- * Fallback for ctx->Driver.DeleteSamplerObject();
- */
-void
-_mesa_delete_sampler_object(struct gl_context *ctx,
- struct gl_sampler_object *sampObj)
-{
- FREE(sampObj);
-}
-
-
-static void GLAPIENTRY
-_mesa_GenSamplers(GLsizei count, GLuint *samplers)
+static void
+create_samplers(struct gl_context *ctx, GLsizei count, GLuint *samplers,
+ const char *caller)
{
- GET_CURRENT_CONTEXT(ctx);
GLuint first;
GLint i;
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- if (MESA_VERBOSE & VERBOSE_API)
- _mesa_debug(ctx, "glGenSamplers(%d)\n", count);
-
- if (count < 0) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glGenSamplers");
- return;
- }
-
if (!samplers)
return;
+ _mesa_HashLockMutex(ctx->Shared->SamplerObjects);
+
first = _mesa_HashFindFreeKeyBlock(ctx->Shared->SamplerObjects, count);
/* Insert the ID and pointer to new sampler object into hash table */
for (i = 0; i < count; i++) {
- struct gl_sampler_object *sampObj =
- ctx->Driver.NewSamplerObject(ctx, first + i);
- _mesa_HashInsert(ctx->Shared->SamplerObjects, first + i, sampObj);
- samplers[i] = first + i;
+ struct gl_sampler_object *sampObj;
+ GLuint name = first + i;
+
+ sampObj = ctx->Driver.NewSamplerObject(ctx, name);
+ if (!sampObj) {
+ _mesa_HashUnlockMutex(ctx->Shared->SamplerObjects);
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", caller);
+ return;
+ }
+
+ _mesa_HashInsertLocked(ctx->Shared->SamplerObjects, name, sampObj);
+ samplers[i] = name;
}
-}
+ _mesa_HashUnlockMutex(ctx->Shared->SamplerObjects);
+}
-static void GLAPIENTRY
-_mesa_DeleteSamplers(GLsizei count, const GLuint *samplers)
+static void
+create_samplers_err(struct gl_context *ctx, GLsizei count, GLuint *samplers,
+ const char *caller)
{
- GET_CURRENT_CONTEXT(ctx);
- GLsizei i;
- ASSERT_OUTSIDE_BEGIN_END(ctx);
- FLUSH_VERTICES(ctx, 0);
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "%s(%d)\n", caller, count);
if (count < 0) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteSamplers(count)");
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s(n<0)", caller);
return;
}
- _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
+ create_samplers(ctx, count, samplers, caller);
+}
- for (i = 0; i < count; i++) {
+void GLAPIENTRY
+_mesa_GenSamplers_no_error(GLsizei count, GLuint *samplers)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ create_samplers(ctx, count, samplers, "glGenSamplers");
+}
+
+void GLAPIENTRY
+_mesa_GenSamplers(GLsizei count, GLuint *samplers)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ create_samplers_err(ctx, count, samplers, "glGenSamplers");
+}
+
+void GLAPIENTRY
+_mesa_CreateSamplers_no_error(GLsizei count, GLuint *samplers)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ create_samplers(ctx, count, samplers, "glCreateSamplers");
+}
+
+void GLAPIENTRY
+_mesa_CreateSamplers(GLsizei count, GLuint *samplers)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ create_samplers_err(ctx, count, samplers, "glCreateSamplers");
+}
+
+
+static void
+delete_samplers(struct gl_context *ctx, GLsizei count, const GLuint *samplers)
+{
+ FLUSH_VERTICES(ctx, 0);
+
+ _mesa_HashLockMutex(ctx->Shared->SamplerObjects);
+
+ for (GLsizei i = 0; i < count; i++) {
if (samplers[i]) {
+ GLuint j;
struct gl_sampler_object *sampObj =
- _mesa_lookup_samplerobj(ctx, samplers[i]);
+ lookup_samplerobj_locked(ctx, samplers[i]);
+
if (sampObj) {
+ /* If the sampler is currently bound, unbind it. */
+ for (j = 0; j < ctx->Const.MaxCombinedTextureImageUnits; j++) {
+ if (ctx->Texture.Unit[j].Sampler == sampObj) {
+ FLUSH_VERTICES(ctx, _NEW_TEXTURE_OBJECT);
+ _mesa_reference_sampler_object(ctx, &ctx->Texture.Unit[j].Sampler, NULL);
+ }
+ }
+
/* The ID is immediately freed for re-use */
- _mesa_HashRemove(ctx->Shared->SamplerObjects, samplers[i]);
+ _mesa_HashRemoveLocked(ctx->Shared->SamplerObjects, samplers[i]);
/* But the object exists until its reference count goes to zero */
_mesa_reference_sampler_object(ctx, &sampObj, NULL);
}
}
}
- _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
+ _mesa_HashUnlockMutex(ctx->Shared->SamplerObjects);
}
-static GLboolean GLAPIENTRY
-_mesa_IsSampler(GLuint sampler)
+void GLAPIENTRY
+_mesa_DeleteSamplers_no_error(GLsizei count, const GLuint *samplers)
{
- struct gl_sampler_object *sampObj;
GET_CURRENT_CONTEXT(ctx);
+ delete_samplers(ctx, count, samplers);
+}
- ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
- if (sampler == 0)
- return GL_FALSE;
+void GLAPIENTRY
+_mesa_DeleteSamplers(GLsizei count, const GLuint *samplers)
+{
+ GET_CURRENT_CONTEXT(ctx);
- sampObj = _mesa_lookup_samplerobj(ctx, sampler);
+ if (count < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteSamplers(count)");
+ return;
+ }
- return sampObj != NULL;
+ delete_samplers(ctx, count, samplers);
}
-static void GLAPIENTRY
-_mesa_BindSampler(GLuint unit, GLuint sampler)
+GLboolean GLAPIENTRY
+_mesa_IsSampler(GLuint sampler)
{
- struct gl_sampler_object *sampObj;
GET_CURRENT_CONTEXT(ctx);
- if (unit >= ctx->Const.MaxTextureImageUnits) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glBindSampler(unit %u)", unit);
- return;
+ ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
+
+ return _mesa_lookup_samplerobj(ctx, sampler) != NULL;
+}
+
+void
+_mesa_bind_sampler(struct gl_context *ctx, GLuint unit,
+ struct gl_sampler_object *sampObj)
+{
+ if (ctx->Texture.Unit[unit].Sampler != sampObj) {
+ FLUSH_VERTICES(ctx, _NEW_TEXTURE_OBJECT);
}
+ _mesa_reference_sampler_object(ctx, &ctx->Texture.Unit[unit].Sampler,
+ sampObj);
+}
+
+static ALWAYS_INLINE void
+bind_sampler(struct gl_context *ctx, GLuint unit, GLuint sampler, bool no_error)
+{
+ struct gl_sampler_object *sampObj;
+
if (sampler == 0) {
/* Use the default sampler object, the one contained in the texture
* object.
*/
sampObj = NULL;
- }
- else {
+ } else {
/* user-defined sampler object */
sampObj = _mesa_lookup_samplerobj(ctx, sampler);
- if (!sampObj) {
+ if (!no_error && !sampObj) {
_mesa_error(ctx, GL_INVALID_OPERATION, "glBindSampler(sampler)");
return;
}
}
- if (ctx->Texture.Unit[unit].Sampler != sampObj) {
- FLUSH_VERTICES(ctx, _NEW_TEXTURE);
+ /* bind new sampler */
+ _mesa_bind_sampler(ctx, unit, sampObj);
+}
+
+void GLAPIENTRY
+_mesa_BindSampler_no_error(GLuint unit, GLuint sampler)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ bind_sampler(ctx, unit, sampler, true);
+}
+
+void GLAPIENTRY
+_mesa_BindSampler(GLuint unit, GLuint sampler)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ if (unit >= ctx->Const.MaxCombinedTextureImageUnits) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glBindSampler(unit %u)", unit);
+ return;
}
- /* bind new sampler */
- _mesa_reference_sampler_object(ctx, &ctx->Texture.Unit[unit].Sampler,
- sampObj);
+ bind_sampler(ctx, unit, sampler, false);
+}
+
+
+static ALWAYS_INLINE void
+bind_samplers(struct gl_context *ctx, GLuint first, GLsizei count,
+ const GLuint *samplers, bool no_error)
+{
+ GLsizei i;
+
+ FLUSH_VERTICES(ctx, 0);
+
+ if (samplers) {
+ /* Note that the error semantics for multi-bind commands differ from
+ * those of other GL commands.
+ *
+ * The Issues section in the ARB_multi_bind spec says:
+ *
+ * "(11) Typically, OpenGL specifies that if an error is generated by
+ * a command, that command has no effect. This is somewhat
+ * unfortunate for multi-bind commands, because it would require
+ * a first pass to scan the entire list of bound objects for
+ * errors and then a second pass to actually perform the
+ * bindings. Should we have different error semantics?
+ *
+ * RESOLVED: Yes. In this specification, when the parameters for
+ * one of the <count> binding points are invalid, that binding
+ * point is not updated and an error will be generated. However,
+ * other binding points in the same command will be updated if
+ * their parameters are valid and no other error occurs."
+ */
+
+ _mesa_HashLockMutex(ctx->Shared->SamplerObjects);
+
+ for (i = 0; i < count; i++) {
+ const GLuint unit = first + i;
+ struct gl_sampler_object * const currentSampler =
+ ctx->Texture.Unit[unit].Sampler;
+ struct gl_sampler_object *sampObj;
+
+ if (samplers[i] != 0) {
+ if (currentSampler && currentSampler->Name == samplers[i])
+ sampObj = currentSampler;
+ else
+ sampObj = lookup_samplerobj_locked(ctx, samplers[i]);
+
+ /* The ARB_multi_bind spec says:
+ *
+ * "An INVALID_OPERATION error is generated if any value
+ * in <samplers> is not zero or the name of an existing
+ * sampler object (per binding)."
+ */
+ if (!no_error && !sampObj) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBindSamplers(samplers[%d]=%u is not zero or "
+ "the name of an existing sampler object)",
+ i, samplers[i]);
+ continue;
+ }
+ } else {
+ sampObj = NULL;
+ }
+
+ /* Bind the new sampler */
+ if (sampObj != currentSampler) {
+ _mesa_reference_sampler_object(ctx,
+ &ctx->Texture.Unit[unit].Sampler,
+ sampObj);
+ ctx->NewState |= _NEW_TEXTURE_OBJECT;
+ }
+ }
+
+ _mesa_HashUnlockMutex(ctx->Shared->SamplerObjects);
+ } else {
+ /* Unbind all samplers in the range <first> through <first>+<count>-1 */
+ for (i = 0; i < count; i++) {
+ const GLuint unit = first + i;
+
+ if (ctx->Texture.Unit[unit].Sampler) {
+ _mesa_reference_sampler_object(ctx,
+ &ctx->Texture.Unit[unit].Sampler,
+ NULL);
+ ctx->NewState |= _NEW_TEXTURE_OBJECT;
+ }
+ }
+ }
+}
+
+
+void GLAPIENTRY
+_mesa_BindSamplers_no_error(GLuint first, GLsizei count, const GLuint *samplers)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ bind_samplers(ctx, first, count, samplers, true);
+}
+
+
+void GLAPIENTRY
+_mesa_BindSamplers(GLuint first, GLsizei count, const GLuint *samplers)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ /* The ARB_multi_bind spec says:
+ *
+ * "An INVALID_OPERATION error is generated if <first> + <count> is
+ * greater than the number of texture image units supported by
+ * the implementation."
+ */
+ if (first + count > ctx->Const.MaxCombinedTextureImageUnits) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBindSamplers(first=%u + count=%d > the value of "
+ "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS=%u)",
+ first, count, ctx->Const.MaxCombinedTextureImageUnits);
+ return;
+ }
+
+ bind_samplers(ctx, first, count, samplers, false);
}
case GL_CLAMP:
case GL_CLAMP_TO_EDGE:
case GL_REPEAT:
+ case GL_MIRRORED_REPEAT:
return GL_TRUE;
case GL_CLAMP_TO_BORDER:
return e->ARB_texture_border_clamp;
- case GL_MIRRORED_REPEAT:
- return e->ARB_texture_mirrored_repeat;
case GL_MIRROR_CLAMP_EXT:
return e->ATI_texture_mirror_once || e->EXT_texture_mirror_clamp;
case GL_MIRROR_CLAMP_TO_EDGE_EXT:
- return e->ATI_texture_mirror_once || e->EXT_texture_mirror_clamp;
+ return e->ATI_texture_mirror_once || e->EXT_texture_mirror_clamp || e->ARB_texture_mirror_clamp_to_edge;
case GL_MIRROR_CLAMP_TO_BORDER_EXT:
return e->EXT_texture_mirror_clamp;
default:
/**
* This is called just prior to changing any sampler object state.
*/
-static INLINE void
+static inline void
flush(struct gl_context *ctx)
{
- FLUSH_VERTICES(ctx, _NEW_TEXTURE);
+ FLUSH_VERTICES(ctx, _NEW_TEXTURE_OBJECT);
}
+void
+_mesa_set_sampler_wrap(struct gl_context *ctx, struct gl_sampler_object *samp,
+ GLenum s, GLenum t, GLenum r)
+{
+ assert(validate_texture_wrap_mode(ctx, s));
+ assert(validate_texture_wrap_mode(ctx, t));
+ assert(validate_texture_wrap_mode(ctx, r));
+
+ if (samp->WrapS == s && samp->WrapT == t && samp->WrapR == r)
+ return;
+
+ flush(ctx);
+ samp->WrapS = s;
+ samp->WrapT = t;
+ samp->WrapR = r;
+}
#define INVALID_PARAM 0x100
#define INVALID_PNAME 0x101
return INVALID_PARAM;
}
+void
+_mesa_set_sampler_filters(struct gl_context *ctx,
+ struct gl_sampler_object *samp,
+ GLenum min_filter, GLenum mag_filter)
+{
+ assert(min_filter == GL_NEAREST ||
+ min_filter == GL_LINEAR ||
+ min_filter == GL_NEAREST_MIPMAP_NEAREST ||
+ min_filter == GL_LINEAR_MIPMAP_NEAREST ||
+ min_filter == GL_NEAREST_MIPMAP_LINEAR ||
+ min_filter == GL_LINEAR_MIPMAP_LINEAR);
+ assert(mag_filter == GL_NEAREST ||
+ mag_filter == GL_LINEAR);
+
+ if (samp->MinFilter == min_filter && samp->MagFilter == mag_filter)
+ return;
+
+ flush(ctx);
+ samp->MinFilter = min_filter;
+ samp->MagFilter = mag_filter;
+}
static GLuint
set_sampler_min_filter(struct gl_context *ctx, struct gl_sampler_object *samp,
static GLuint
set_sampler_max_lod(struct gl_context *ctx, struct gl_sampler_object *samp,
- GLint param)
+ GLfloat param)
{
if (samp->MaxLod == param)
return GL_FALSE;
set_sampler_compare_mode(struct gl_context *ctx,
struct gl_sampler_object *samp, GLint param)
{
+ /* If GL_ARB_shadow is not supported, don't report an error. The
+ * sampler object extension spec isn't clear on this extension interaction.
+ * Silences errors with Wine on older GPUs such as R200.
+ */
if (!ctx->Extensions.ARB_shadow)
- return INVALID_PNAME;
+ return GL_FALSE;
if (samp->CompareMode == param)
return GL_FALSE;
set_sampler_compare_func(struct gl_context *ctx,
struct gl_sampler_object *samp, GLint param)
{
+ /* If GL_ARB_shadow is not supported, don't report an error. The
+ * sampler object extension spec isn't clear on this extension interaction.
+ * Silences errors with Wine on older GPUs such as R200.
+ */
if (!ctx->Extensions.ARB_shadow)
- return INVALID_PNAME;
+ return GL_FALSE;
if (samp->CompareFunc == param)
return GL_FALSE;
switch (param) {
case GL_LEQUAL:
case GL_GEQUAL:
- flush(ctx);
- samp->CompareFunc = param;
- return GL_TRUE;
case GL_EQUAL:
case GL_NOTEQUAL:
case GL_LESS:
case GL_GREATER:
case GL_ALWAYS:
case GL_NEVER:
- if (ctx->Extensions.EXT_shadow_funcs) {
- flush(ctx);
- samp->CompareFunc = param;
- return GL_TRUE;
- }
- /* fall-through */
+ flush(ctx);
+ samp->CompareFunc = param;
+ return GL_TRUE;
default:
return INVALID_PARAM;
}
if (samp->MaxAnisotropy == param)
return GL_FALSE;
- if (param < 1.0)
+ if (param < 1.0F)
return INVALID_VALUE;
flush(ctx);
}
-static void GLAPIENTRY
+static GLuint
+set_sampler_cube_map_seamless(struct gl_context *ctx,
+ struct gl_sampler_object *samp, GLboolean param)
+{
+ if (!_mesa_is_desktop_gl(ctx)
+ || !ctx->Extensions.AMD_seamless_cubemap_per_texture)
+ return INVALID_PNAME;
+
+ if (samp->CubeMapSeamless == param)
+ return GL_FALSE;
+
+ if (param != GL_TRUE && param != GL_FALSE)
+ return INVALID_VALUE;
+
+ flush(ctx);
+ samp->CubeMapSeamless = param;
+ return GL_TRUE;
+}
+
+void
+_mesa_set_sampler_srgb_decode(struct gl_context *ctx,
+ struct gl_sampler_object *samp, GLenum param)
+{
+ assert(param == GL_DECODE_EXT || param == GL_SKIP_DECODE_EXT);
+
+ flush(ctx);
+ samp->sRGBDecode = param;
+}
+
+static GLuint
+set_sampler_srgb_decode(struct gl_context *ctx,
+ struct gl_sampler_object *samp, GLenum param)
+{
+ if (!ctx->Extensions.EXT_texture_sRGB_decode)
+ return INVALID_PNAME;
+
+ if (samp->sRGBDecode == param)
+ return GL_FALSE;
+
+ /* The EXT_texture_sRGB_decode spec says:
+ *
+ * "INVALID_ENUM is generated if the <pname> parameter of
+ * TexParameter[i,f,Ii,Iui][v][EXT],
+ * MultiTexParameter[i,f,Ii,Iui][v]EXT,
+ * TextureParameter[i,f,Ii,Iui][v]EXT, SamplerParameter[i,f,Ii,Iui][v]
+ * is TEXTURE_SRGB_DECODE_EXT when the <param> parameter is not one of
+ * DECODE_EXT or SKIP_DECODE_EXT.
+ *
+ * Returning INVALID_PARAM makes that happen.
+ */
+ if (param != GL_DECODE_EXT && param != GL_SKIP_DECODE_EXT)
+ return INVALID_PARAM;
+
+ flush(ctx);
+ samp->sRGBDecode = param;
+ return GL_TRUE;
+}
+
+static struct gl_sampler_object *
+sampler_parameter_error_check(struct gl_context *ctx, GLuint sampler,
+ bool get, const char *name)
+{
+ struct gl_sampler_object *sampObj;
+
+ sampObj = _mesa_lookup_samplerobj(ctx, sampler);
+ if (!sampObj) {
+ /* OpenGL 4.5 spec, section "8.2 Sampler Objects", page 176 of the PDF
+ * states:
+ *
+ * "An INVALID_OPERATION error is generated if sampler is not the name
+ * of a sampler object previously returned from a call to
+ * GenSamplers."
+ */
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid sampler)", name);
+ return NULL;
+ }
+
+ if (!get && sampObj->HandleAllocated) {
+ /* The ARB_bindless_texture spec says:
+ *
+ * "The error INVALID_OPERATION is generated by SamplerParameter* if
+ * <sampler> identifies a sampler object referenced by one or more
+ * texture handles."
+ */
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s(immutable sampler)", name);
+ return NULL;
+ }
+
+ return sampObj;
+}
+
+void GLAPIENTRY
_mesa_SamplerParameteri(GLuint sampler, GLenum pname, GLint param)
{
struct gl_sampler_object *sampObj;
GLuint res;
GET_CURRENT_CONTEXT(ctx);
- sampObj = _mesa_lookup_samplerobj(ctx, sampler);
- if (!sampObj) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glSamplerParameteri(sampler %u)",
- sampler);
+ sampObj = sampler_parameter_error_check(ctx, sampler, false,
+ "glSamplerParameteri");
+ if (!sampObj)
return;
- }
switch (pname) {
case GL_TEXTURE_WRAP_S:
case GL_TEXTURE_MAX_ANISOTROPY_EXT:
res = set_sampler_max_anisotropy(ctx, sampObj, (GLfloat) param);
break;
+ case GL_TEXTURE_CUBE_MAP_SEAMLESS:
+ res = set_sampler_cube_map_seamless(ctx, sampObj, param);
+ break;
+ case GL_TEXTURE_SRGB_DECODE_EXT:
+ res = set_sampler_srgb_decode(ctx, sampObj, param);
+ break;
case GL_TEXTURE_BORDER_COLOR:
/* fall-through */
default:
break;
case INVALID_PNAME:
_mesa_error(ctx, GL_INVALID_ENUM, "glSamplerParameteri(pname=%s)\n",
- _mesa_lookup_enum_by_nr(pname));
+ _mesa_enum_to_string(pname));
break;
case INVALID_PARAM:
_mesa_error(ctx, GL_INVALID_ENUM, "glSamplerParameteri(param=%d)\n",
}
-static void GLAPIENTRY
+void GLAPIENTRY
_mesa_SamplerParameterf(GLuint sampler, GLenum pname, GLfloat param)
{
struct gl_sampler_object *sampObj;
GLuint res;
GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- sampObj = _mesa_lookup_samplerobj(ctx, sampler);
- if (!sampObj) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glSamplerParameterf(sampler %u)",
- sampler);
+ sampObj = sampler_parameter_error_check(ctx, sampler, false,
+ "glSamplerParameterf");
+ if (!sampObj)
return;
- }
switch (pname) {
case GL_TEXTURE_WRAP_S:
case GL_TEXTURE_MAX_ANISOTROPY_EXT:
res = set_sampler_max_anisotropy(ctx, sampObj, param);
break;
+ case GL_TEXTURE_CUBE_MAP_SEAMLESS:
+ res = set_sampler_cube_map_seamless(ctx, sampObj, (GLboolean) param);
+ break;
+ case GL_TEXTURE_SRGB_DECODE_EXT:
+ res = set_sampler_srgb_decode(ctx, sampObj, (GLenum) param);
+ break;
case GL_TEXTURE_BORDER_COLOR:
/* fall-through */
default:
break;
case INVALID_PNAME:
_mesa_error(ctx, GL_INVALID_ENUM, "glSamplerParameterf(pname=%s)\n",
- _mesa_lookup_enum_by_nr(pname));
+ _mesa_enum_to_string(pname));
break;
case INVALID_PARAM:
_mesa_error(ctx, GL_INVALID_ENUM, "glSamplerParameterf(param=%f)\n",
}
}
-static void GLAPIENTRY
+void GLAPIENTRY
_mesa_SamplerParameteriv(GLuint sampler, GLenum pname, const GLint *params)
{
struct gl_sampler_object *sampObj;
GLuint res;
GET_CURRENT_CONTEXT(ctx);
- sampObj = _mesa_lookup_samplerobj(ctx, sampler);
- if (!sampObj) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glSamplerParameteriv(sampler %u)",
- sampler);
+ sampObj = sampler_parameter_error_check(ctx, sampler, false,
+ "glSamplerParameteriv");
+ if (!sampObj)
return;
- }
switch (pname) {
case GL_TEXTURE_WRAP_S:
case GL_TEXTURE_MAX_ANISOTROPY_EXT:
res = set_sampler_max_anisotropy(ctx, sampObj, (GLfloat) params[0]);
break;
+ case GL_TEXTURE_CUBE_MAP_SEAMLESS:
+ res = set_sampler_cube_map_seamless(ctx, sampObj, params[0]);
+ break;
+ case GL_TEXTURE_SRGB_DECODE_EXT:
+ res = set_sampler_srgb_decode(ctx, sampObj, params[0]);
+ break;
case GL_TEXTURE_BORDER_COLOR:
{
GLfloat c[4];
break;
case INVALID_PNAME:
_mesa_error(ctx, GL_INVALID_ENUM, "glSamplerParameteriv(pname=%s)\n",
- _mesa_lookup_enum_by_nr(pname));
+ _mesa_enum_to_string(pname));
break;
case INVALID_PARAM:
_mesa_error(ctx, GL_INVALID_ENUM, "glSamplerParameteriv(param=%d)\n",
}
}
-static void GLAPIENTRY
+void GLAPIENTRY
_mesa_SamplerParameterfv(GLuint sampler, GLenum pname, const GLfloat *params)
{
struct gl_sampler_object *sampObj;
GLuint res;
GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- sampObj = _mesa_lookup_samplerobj(ctx, sampler);
- if (!sampObj) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glSamplerParameterfv(sampler %u)",
- sampler);
+ sampObj = sampler_parameter_error_check(ctx, sampler, false,
+ "glSamplerParameterfv");
+ if (!sampObj)
return;
- }
switch (pname) {
case GL_TEXTURE_WRAP_S:
case GL_TEXTURE_MAX_ANISOTROPY_EXT:
res = set_sampler_max_anisotropy(ctx, sampObj, params[0]);
break;
+ case GL_TEXTURE_CUBE_MAP_SEAMLESS:
+ res = set_sampler_cube_map_seamless(ctx, sampObj, (GLboolean) params[0]);
+ break;
+ case GL_TEXTURE_SRGB_DECODE_EXT:
+ res = set_sampler_srgb_decode(ctx, sampObj, (GLenum) params[0]);
+ break;
case GL_TEXTURE_BORDER_COLOR:
res = set_sampler_border_colorf(ctx, sampObj, params);
break;
break;
case INVALID_PNAME:
_mesa_error(ctx, GL_INVALID_ENUM, "glSamplerParameterfv(pname=%s)\n",
- _mesa_lookup_enum_by_nr(pname));
+ _mesa_enum_to_string(pname));
break;
case INVALID_PARAM:
_mesa_error(ctx, GL_INVALID_ENUM, "glSamplerParameterfv(param=%f)\n",
}
}
-static void GLAPIENTRY
+void GLAPIENTRY
_mesa_SamplerParameterIiv(GLuint sampler, GLenum pname, const GLint *params)
{
struct gl_sampler_object *sampObj;
GLuint res;
GET_CURRENT_CONTEXT(ctx);
- sampObj = _mesa_lookup_samplerobj(ctx, sampler);
- if (!sampObj) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glSamplerParameterIiv(sampler %u)",
- sampler);
+ sampObj = sampler_parameter_error_check(ctx, sampler, false,
+ "glSamplerParameterIiv");
+ if (!sampObj)
return;
- }
switch (pname) {
case GL_TEXTURE_WRAP_S:
case GL_TEXTURE_MAX_ANISOTROPY_EXT:
res = set_sampler_max_anisotropy(ctx, sampObj, (GLfloat) params[0]);
break;
+ case GL_TEXTURE_CUBE_MAP_SEAMLESS:
+ res = set_sampler_cube_map_seamless(ctx, sampObj, params[0]);
+ break;
+ case GL_TEXTURE_SRGB_DECODE_EXT:
+ res = set_sampler_srgb_decode(ctx, sampObj, (GLenum) params[0]);
+ break;
case GL_TEXTURE_BORDER_COLOR:
res = set_sampler_border_colori(ctx, sampObj, params);
break;
break;
case INVALID_PNAME:
_mesa_error(ctx, GL_INVALID_ENUM, "glSamplerParameterIiv(pname=%s)\n",
- _mesa_lookup_enum_by_nr(pname));
+ _mesa_enum_to_string(pname));
break;
case INVALID_PARAM:
_mesa_error(ctx, GL_INVALID_ENUM, "glSamplerParameterIiv(param=%d)\n",
}
-static void GLAPIENTRY
+void GLAPIENTRY
_mesa_SamplerParameterIuiv(GLuint sampler, GLenum pname, const GLuint *params)
{
struct gl_sampler_object *sampObj;
GLuint res;
GET_CURRENT_CONTEXT(ctx);
- sampObj = _mesa_lookup_samplerobj(ctx, sampler);
- if (!sampObj) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glSamplerParameterIuiv(sampler %u)",
- sampler);
+ sampObj = sampler_parameter_error_check(ctx, sampler, false,
+ "glSamplerParameterIuiv");
+ if (!sampObj)
return;
- }
switch (pname) {
case GL_TEXTURE_WRAP_S:
case GL_TEXTURE_MAX_ANISOTROPY_EXT:
res = set_sampler_max_anisotropy(ctx, sampObj, (GLfloat) params[0]);
break;
+ case GL_TEXTURE_CUBE_MAP_SEAMLESS:
+ res = set_sampler_cube_map_seamless(ctx, sampObj, params[0]);
+ break;
+ case GL_TEXTURE_SRGB_DECODE_EXT:
+ res = set_sampler_srgb_decode(ctx, sampObj, (GLenum) params[0]);
+ break;
case GL_TEXTURE_BORDER_COLOR:
res = set_sampler_border_colorui(ctx, sampObj, params);
break;
break;
case INVALID_PNAME:
_mesa_error(ctx, GL_INVALID_ENUM, "glSamplerParameterIuiv(pname=%s)\n",
- _mesa_lookup_enum_by_nr(pname));
+ _mesa_enum_to_string(pname));
break;
case INVALID_PARAM:
_mesa_error(ctx, GL_INVALID_ENUM, "glSamplerParameterIuiv(param=%u)\n",
}
-static void GLAPIENTRY
+void GLAPIENTRY
_mesa_GetSamplerParameteriv(GLuint sampler, GLenum pname, GLint *params)
{
struct gl_sampler_object *sampObj;
GET_CURRENT_CONTEXT(ctx);
- sampObj = _mesa_lookup_samplerobj(ctx, sampler);
- if (!sampObj) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glGetSamplerParameteriv(sampler %u)",
- sampler);
+ sampObj = sampler_parameter_error_check(ctx, sampler, true,
+ "glGetSamplerParameteriv");
+ if (!sampObj)
return;
- }
switch (pname) {
case GL_TEXTURE_WRAP_S:
*params = sampObj->MagFilter;
break;
case GL_TEXTURE_MIN_LOD:
- *params = (GLint) sampObj->MinLod;
+ /* GL spec 'Data Conversions' section specifies that floating-point
+ * value in integer Get function is rounded to nearest integer
+ */
+ *params = IROUND(sampObj->MinLod);
break;
case GL_TEXTURE_MAX_LOD:
- *params = (GLint) sampObj->MaxLod;
+ /* GL spec 'Data Conversions' section specifies that floating-point
+ * value in integer Get function is rounded to nearest integer
+ */
+ *params = IROUND(sampObj->MaxLod);
break;
case GL_TEXTURE_LOD_BIAS:
- *params = (GLint) sampObj->LodBias;
+ /* GL spec 'Data Conversions' section specifies that floating-point
+ * value in integer Get function is rounded to nearest integer
+ */
+ *params = IROUND(sampObj->LodBias);
break;
case GL_TEXTURE_COMPARE_MODE:
- if (!ctx->Extensions.ARB_shadow)
- goto invalid_pname;
*params = sampObj->CompareMode;
break;
case GL_TEXTURE_COMPARE_FUNC:
- if (!ctx->Extensions.ARB_shadow)
- goto invalid_pname;
*params = sampObj->CompareFunc;
break;
case GL_TEXTURE_MAX_ANISOTROPY_EXT:
- *params = (GLint) sampObj->MaxAnisotropy;
+ /* GL spec 'Data Conversions' section specifies that floating-point
+ * value in integer Get function is rounded to nearest integer
+ */
+ *params = IROUND(sampObj->MaxAnisotropy);
break;
case GL_TEXTURE_BORDER_COLOR:
params[0] = FLOAT_TO_INT(sampObj->BorderColor.f[0]);
params[2] = FLOAT_TO_INT(sampObj->BorderColor.f[2]);
params[3] = FLOAT_TO_INT(sampObj->BorderColor.f[3]);
break;
+ case GL_TEXTURE_CUBE_MAP_SEAMLESS:
+ if (!ctx->Extensions.AMD_seamless_cubemap_per_texture)
+ goto invalid_pname;
+ *params = sampObj->CubeMapSeamless;
+ break;
+ case GL_TEXTURE_SRGB_DECODE_EXT:
+ if (!ctx->Extensions.EXT_texture_sRGB_decode)
+ goto invalid_pname;
+ *params = (GLenum) sampObj->sRGBDecode;
+ break;
default:
goto invalid_pname;
}
invalid_pname:
_mesa_error(ctx, GL_INVALID_ENUM, "glGetSamplerParameteriv(pname=%s)",
- _mesa_lookup_enum_by_nr(pname));
+ _mesa_enum_to_string(pname));
}
-static void GLAPIENTRY
+void GLAPIENTRY
_mesa_GetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat *params)
{
struct gl_sampler_object *sampObj;
GET_CURRENT_CONTEXT(ctx);
- sampObj = _mesa_lookup_samplerobj(ctx, sampler);
- if (!sampObj) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glGetSamplerParameterfv(sampler %u)",
- sampler);
+ sampObj = sampler_parameter_error_check(ctx, sampler, true,
+ "glGetSamplerParameterfv");
+ if (!sampObj)
return;
- }
switch (pname) {
case GL_TEXTURE_WRAP_S:
*params = sampObj->LodBias;
break;
case GL_TEXTURE_COMPARE_MODE:
- if (!ctx->Extensions.ARB_shadow)
- goto invalid_pname;
*params = (GLfloat) sampObj->CompareMode;
break;
case GL_TEXTURE_COMPARE_FUNC:
- if (!ctx->Extensions.ARB_shadow)
- goto invalid_pname;
*params = (GLfloat) sampObj->CompareFunc;
break;
case GL_TEXTURE_MAX_ANISOTROPY_EXT:
params[2] = sampObj->BorderColor.f[2];
params[3] = sampObj->BorderColor.f[3];
break;
+ case GL_TEXTURE_CUBE_MAP_SEAMLESS:
+ if (!ctx->Extensions.AMD_seamless_cubemap_per_texture)
+ goto invalid_pname;
+ *params = (GLfloat) sampObj->CubeMapSeamless;
+ break;
+ case GL_TEXTURE_SRGB_DECODE_EXT:
+ if (!ctx->Extensions.EXT_texture_sRGB_decode)
+ goto invalid_pname;
+ *params = (GLfloat) sampObj->sRGBDecode;
+ break;
default:
goto invalid_pname;
}
invalid_pname:
_mesa_error(ctx, GL_INVALID_ENUM, "glGetSamplerParameterfv(pname=%s)",
- _mesa_lookup_enum_by_nr(pname));
+ _mesa_enum_to_string(pname));
}
-static void GLAPIENTRY
+void GLAPIENTRY
_mesa_GetSamplerParameterIiv(GLuint sampler, GLenum pname, GLint *params)
{
struct gl_sampler_object *sampObj;
GET_CURRENT_CONTEXT(ctx);
- sampObj = _mesa_lookup_samplerobj(ctx, sampler);
- if (!sampObj) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glGetSamplerParameterIiv(sampler %u)",
- sampler);
+ sampObj = sampler_parameter_error_check(ctx, sampler, true,
+ "glGetSamplerParameterIiv");
+ if (!sampObj)
return;
- }
switch (pname) {
case GL_TEXTURE_WRAP_S:
*params = (GLint) sampObj->LodBias;
break;
case GL_TEXTURE_COMPARE_MODE:
- if (!ctx->Extensions.ARB_shadow)
- goto invalid_pname;
*params = sampObj->CompareMode;
break;
case GL_TEXTURE_COMPARE_FUNC:
- if (!ctx->Extensions.ARB_shadow)
- goto invalid_pname;
*params = sampObj->CompareFunc;
break;
case GL_TEXTURE_MAX_ANISOTROPY_EXT:
params[2] = sampObj->BorderColor.i[2];
params[3] = sampObj->BorderColor.i[3];
break;
+ case GL_TEXTURE_CUBE_MAP_SEAMLESS:
+ if (!ctx->Extensions.AMD_seamless_cubemap_per_texture)
+ goto invalid_pname;
+ *params = sampObj->CubeMapSeamless;
+ break;
+ case GL_TEXTURE_SRGB_DECODE_EXT:
+ if (!ctx->Extensions.EXT_texture_sRGB_decode)
+ goto invalid_pname;
+ *params = (GLenum) sampObj->sRGBDecode;
+ break;
default:
goto invalid_pname;
}
invalid_pname:
_mesa_error(ctx, GL_INVALID_ENUM, "glGetSamplerParameterIiv(pname=%s)",
- _mesa_lookup_enum_by_nr(pname));
+ _mesa_enum_to_string(pname));
}
-static void GLAPIENTRY
+void GLAPIENTRY
_mesa_GetSamplerParameterIuiv(GLuint sampler, GLenum pname, GLuint *params)
{
struct gl_sampler_object *sampObj;
GET_CURRENT_CONTEXT(ctx);
- sampObj = _mesa_lookup_samplerobj(ctx, sampler);
- if (!sampObj) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glGetSamplerParameterIuiv(sampler %u)",
- sampler);
+ sampObj = sampler_parameter_error_check(ctx, sampler, true,
+ "glGetSamplerParameterIuiv");
+ if (!sampObj)
return;
- }
switch (pname) {
case GL_TEXTURE_WRAP_S:
*params = (GLuint) sampObj->LodBias;
break;
case GL_TEXTURE_COMPARE_MODE:
- if (!ctx->Extensions.ARB_shadow)
- goto invalid_pname;
*params = sampObj->CompareMode;
break;
case GL_TEXTURE_COMPARE_FUNC:
- if (!ctx->Extensions.ARB_shadow)
- goto invalid_pname;
*params = sampObj->CompareFunc;
break;
case GL_TEXTURE_MAX_ANISOTROPY_EXT:
params[2] = sampObj->BorderColor.ui[2];
params[3] = sampObj->BorderColor.ui[3];
break;
+ case GL_TEXTURE_CUBE_MAP_SEAMLESS:
+ if (!ctx->Extensions.AMD_seamless_cubemap_per_texture)
+ goto invalid_pname;
+ *params = sampObj->CubeMapSeamless;
+ break;
+ case GL_TEXTURE_SRGB_DECODE_EXT:
+ if (!ctx->Extensions.EXT_texture_sRGB_decode)
+ goto invalid_pname;
+ *params = (GLenum) sampObj->sRGBDecode;
+ break;
default:
goto invalid_pname;
}
invalid_pname:
_mesa_error(ctx, GL_INVALID_ENUM, "glGetSamplerParameterIuiv(pname=%s)",
- _mesa_lookup_enum_by_nr(pname));
+ _mesa_enum_to_string(pname));
}
_mesa_init_sampler_object_functions(struct dd_function_table *driver)
{
driver->NewSamplerObject = _mesa_new_sampler_object;
- driver->DeleteSamplerObject = _mesa_delete_sampler_object;
-}
-
-
-void
-_mesa_init_sampler_object_dispatch(struct _glapi_table *disp)
-{
- SET_GenSamplers(disp, _mesa_GenSamplers);
- SET_DeleteSamplers(disp, _mesa_DeleteSamplers);
- SET_IsSampler(disp, _mesa_IsSampler);
- SET_BindSampler(disp, _mesa_BindSampler);
- SET_SamplerParameteri(disp, _mesa_SamplerParameteri);
- SET_SamplerParameterf(disp, _mesa_SamplerParameterf);
- SET_SamplerParameteriv(disp, _mesa_SamplerParameteriv);
- SET_SamplerParameterfv(disp, _mesa_SamplerParameterfv);
- SET_SamplerParameterIiv(disp, _mesa_SamplerParameterIiv);
- SET_SamplerParameterIuiv(disp, _mesa_SamplerParameterIuiv);
- SET_GetSamplerParameteriv(disp, _mesa_GetSamplerParameteriv);
- SET_GetSamplerParameterfv(disp, _mesa_GetSamplerParameterfv);
- SET_GetSamplerParameterIiv(disp, _mesa_GetSamplerParameterIiv);
- SET_GetSamplerParameterIuiv(disp, _mesa_GetSamplerParameterIuiv);
}