/* Copyright (c) 2001, Stanford University
* All rights reserved
*
* See the file LICENSE.txt for information on redistributing this software.
*/
#include "state.h"
#include "state/cr_statetypes.h"
#include "state/cr_statefuncs.h"
#include "state_internals.h"
#include "cr_mem.h"
void
crStateOcclusionInit(CRContext *ctx)
{
CROcclusionState *o = &ctx->occlusion;
o->objects = crAllocHashtable();
o->currentQueryObject = 0;
}
void
crStateOcclusionDestroy(CRContext *ctx)
{
CROcclusionState *o = &(ctx->occlusion);
crFreeHashtable(o->objects, crFree);
}
static CROcclusionObject *
NewQueryObject(GLenum target, GLuint id)
{
CROcclusionObject *q = (CROcclusionObject *) crAlloc(sizeof(CROcclusionObject));
if (q) {
q->target = target;
q->name = id;
q->passedCounter = 0;
q->active = GL_FALSE;
}
return q;
}
void STATE_APIENTRY
crStateDeleteQueriesARB(GLsizei n, const GLuint *ids)
{
CRContext *g = GetCurrentContext();
CROcclusionState *o = &(g->occlusion);
/*CRStateBits *sb = GetCurrentBits();*/
/*CROcclusionBits *bb = &(sb->occlusion);*/
int i;
FLUSH();
if (g->current.inBeginEnd) {
crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION,
"glDeleteQueriesARB called in Begin/End");
return;
}
if (n < 0) {
crStateError(__LINE__, __FILE__, GL_INVALID_VALUE,
"glDeleteQueriesARB(n < 0)");
return;
}
for (i = 0; i < n; i++) {
if (ids[i]) {
CROcclusionObject *q = (CROcclusionObject *)
crHashtableSearch(o->objects, ids[i]);
if (q) {
crHashtableDelete(o->objects, ids[i], crFree);
}
}
}
}
void STATE_APIENTRY
crStateGenQueriesARB(GLsizei n, GLuint * queries)
{
CRContext *g = GetCurrentContext();
CROcclusionState *o = &(g->occlusion);
GLint start;
FLUSH();
if (g->current.inBeginEnd) {
crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION,
"glGenQueriesARB called in Begin/End");
return;
}
if (n < 0) {
crStateError(__LINE__, __FILE__, GL_INVALID_VALUE,
"glGenQueriesARB(n < 0)");
return;
}
start = crHashtableAllocKeys(o->objects, n);
if (start) {
GLint i;
for (i = 0; i < n; i++)
queries[i] = (GLuint) (start + i);
}
else {
crStateError(__LINE__, __FILE__, GL_OUT_OF_MEMORY, "glGenQueriesARB");
}
}
GLboolean STATE_APIENTRY
crStateIsQueryARB(GLuint id)
{
CRContext *g = GetCurrentContext();
CROcclusionState *o = &(g->occlusion);
FLUSH();
if (g->current.inBeginEnd) {
crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION,
"glIsQueryARB called in begin/end");
return GL_FALSE;
}
if (id && crHashtableIsKeyUsed(o->objects, id))
return GL_TRUE;
else
return GL_FALSE;
}
void STATE_APIENTRY
crStateGetQueryivARB(GLenum target, GLenum pname, GLint *params)
{
CRContext *g = GetCurrentContext();
CROcclusionState *o = &(g->occlusion);
FLUSH();
if (g->current.inBeginEnd) {
crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION,
"glGetGetQueryivARB called in begin/end");
return;
}
switch (pname) {
case GL_QUERY_COUNTER_BITS_ARB:
*params = 8 * sizeof(GLuint);
break;
case GL_CURRENT_QUERY_ARB:
*params = o->currentQueryObject;
break;
default:
crStateError(__LINE__, __FILE__, GL_INVALID_ENUM,
"glGetGetQueryivARB(pname)");
return;
}
}
void STATE_APIENTRY
crStateGetQueryObjectivARB(GLuint id, GLenum pname, GLint *params)
{
CRContext *g = GetCurrentContext();
CROcclusionState *o = &(g->occlusion);
CROcclusionObject *q;
FLUSH();
if (g->current.inBeginEnd) {
crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION,
"glGetGetQueryObjectivARB called in begin/end");
return;
}
q = (CROcclusionObject *) crHashtableSearch(o->objects, id);
if (!q || q->active) {
crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION,
"glGetQueryObjectivARB");
return;
}
switch (pname) {
case GL_QUERY_RESULT_ARB:
*params = q->passedCounter;
break;
case GL_QUERY_RESULT_AVAILABLE_ARB:
*params = GL_TRUE;
break;
default:
crStateError(__LINE__, __FILE__, GL_INVALID_ENUM,
"glGetQueryObjectivARB(pname)");
return;
}
}
void STATE_APIENTRY
crStateGetQueryObjectuivARB(GLuint id, GLenum pname, GLuint *params)
{
CRContext *g = GetCurrentContext();
CROcclusionState *o = &(g->occlusion);
CROcclusionObject *q;
FLUSH();
if (g->current.inBeginEnd) {
crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION,
"glGetGetQueryObjectuivARB called in begin/end");
return;
}
q = (CROcclusionObject *) crHashtableSearch(o->objects, id);
if (!q || q->active) {
crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION,
"glGetQueryObjectuivARB");
return;
}
switch (pname) {
case GL_QUERY_RESULT_ARB:
*params = q->passedCounter;
break;
case GL_QUERY_RESULT_AVAILABLE_ARB:
/* XXX revisit when we have a hardware implementation! */
*params = GL_TRUE;
break;
default:
crStateError(__LINE__, __FILE__, GL_INVALID_ENUM,
"glGetQueryObjectuivARB(pname)");
return;
}
}
void STATE_APIENTRY
crStateBeginQueryARB(GLenum target, GLuint id)
{
CRContext *g = GetCurrentContext();
CROcclusionState *o = &(g->occlusion);
CROcclusionObject *q;
FLUSH();
if (g->current.inBeginEnd) {
crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION,
"glGetGetQueryObjectuivARB called in begin/end");
return;
}
if (target != GL_SAMPLES_PASSED_ARB) {
crStateError(__LINE__, __FILE__, GL_INVALID_ENUM,
"glBeginQueryARB(target)");
return;
}
if (o->currentQueryObject) {
crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION,
"glBeginQueryARB(target)");
return;
}
q = (CROcclusionObject *) crHashtableSearch(o->objects, id);
if (q && q->active) {
crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, "glBeginQueryARB");
return;
}
else if (!q) {
q = NewQueryObject(target, id);
if (!q) {
crStateError(__LINE__, __FILE__, GL_OUT_OF_MEMORY, "glBeginQueryARB");
return;
}
crHashtableAdd(o->objects, id, q);
}
q->active = GL_TRUE;
q->passedCounter = 0;
q->active = GL_TRUE;
q->passedCounter = 0;
o->currentQueryObject = id;
}
void STATE_APIENTRY
crStateEndQueryARB(GLenum target)
{
CRContext *g = GetCurrentContext();
CROcclusionState *o = &(g->occlusion);
CROcclusionObject *q;
FLUSH();
if (g->current.inBeginEnd) {
crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION,
"glGetGetQueryObjectuivARB called in begin/end");
return;
}
if (target != GL_SAMPLES_PASSED_ARB) {
crStateError(__LINE__, __FILE__, GL_INVALID_ENUM, "glEndQueryARB(target)");
return;
}
q = (CROcclusionObject *) crHashtableSearch(o->objects, o->currentQueryObject);
if (!q || !q->active) {
crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION,
"glEndQueryARB with glBeginQueryARB");
return;
}
q->passedCounter = 0;
q->active = GL_FALSE;
o->currentQueryObject = 0;
}
void crStateOcclusionDiff(CROcclusionBits *bb, CRbitvalue *bitID,
CRContext *fromCtx, CRContext *toCtx)
{
/* Apparently, no occlusion state differencing needed */
}
/*
* XXX this function might need some testing/fixing.
*/
void crStateOcclusionSwitch(CROcclusionBits *bb, CRbitvalue *bitID,
CRContext *fromCtx, CRContext *toCtx)
{
/* Apparently, no occlusion state switching needed */
/* Note: we better not do a switch while we're inside a glBeginQuery/
* glEndQuery sequence.
*/
CRASSERT(!fromCtx->occlusion.currentQueryObject);
}