windows-nt/Source/XPSP1/NT/multimedia/opengl/server/soft/so_txobj.c
2020-09-26 16:20:57 +08:00

747 lines
23 KiB
C

/*
** Copyright 1991,1992, Silicon Graphics, Inc.
** All Rights Reserved.
**
** This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
** the contents of this file may not be disclosed to third parties, copied or
** duplicated in any form, in whole or in part, without the prior written
** permission of Silicon Graphics, Inc.
**
** RESTRICTED RIGHTS LEGEND:
** Use, duplication or disclosure by the Government is subject to restrictions
** as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
** and Computer Software clause at DFARS 252.227-7013, and/or in similar or
** successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
** rights reserved under the Copyright Laws of the United States.
**
*/
#include "precomp.h"
#pragma hdrstop
#include <namesint.h>
#include <glmath.h>
#include <devlock.h>
/************************************************************************/
/*
** Texture Object routines.
*/
/************************************************************************/
#define __GL_CHECK_VALID_N_PARAM(failStatement) \
if (n < 0) { \
__glSetError(GL_INVALID_VALUE); \
} \
if (n == 0) { \
failStatement; \
} \
GLvoid APIPRIVATE __glim_GenTextures(GLsizei n, GLuint* textures)
{
__GL_SETUP_NOT_IN_BEGIN();
__GL_CHECK_VALID_N_PARAM(return);
if (NULL == textures) return;
ASSERTOPENGL(NULL != gc->texture.shared->namesArray,
"No texture names array\n");
__glNamesGenNames(gc, gc->texture.shared->namesArray, n, textures);
}
GLvoid APIPRIVATE __glim_DeleteTextures(GLsizei n, const GLuint* textures)
{
GLuint start, rangeVal, numTextures, targetIndex, i;
__GLnamesArray *array;
__GLtextureObject *texobj, **pBoundTexture;
__GL_SETUP_NOT_IN_BEGIN();
__GL_CHECK_VALID_N_PARAM(return);
array = gc->texture.shared->namesArray;
numTextures = gc->constants.numberOfTextures;
/*
** Send the texture names in ranges to the names module to be
** deleted. Ignore any references to default textures.
** If a texture that is being deleted is currently bound,
** bind the default texture to its target.
** The names routine ignores any names that don't refer to
** textures.
*/
start = rangeVal = textures[0];
for (i=0; i < (GLuint)n; i++, rangeVal++) {
if (0 == textures[i]) { /* skip default textures */
/* delete up to this one */
__glNamesDeleteRange(gc,array,start,rangeVal-start);
/* skip over this one by setting start to the next one */
start = textures[i+1];
rangeVal = start-1; /* because it gets incremented later */
continue;
}
/*
** If the texture is currently bound, bind the defaultTexture
** to its target. The problem here is identifying the target.
** One way is to look up the texobj with the name. Another is
** to look through all of the currently bound textures and
** check each for the name. It has been implemented with the
** assumption that looking through the currently bound textures
** is faster than retrieving the texobj that corresponds to
** the name.
*/
for (targetIndex=0, pBoundTexture = gc->texture.boundTextures;
targetIndex < numTextures; targetIndex++, pBoundTexture++) {
/* Is the texture currently bound? */
if (*pBoundTexture != &gc->texture.ddtex.texobj &&
(*pBoundTexture)->texture.map.texobjs.name == textures[i]) {
__GLperTextureState *pts;
pts = &gc->state.texture.texture[targetIndex];
/* if we don't unlock it, it won't get deleted */
__glNamesUnlockData(gc, *pBoundTexture, __glCleanupTexObj);
/* bind the default texture to this target */
texobj = gc->texture.defaultTextures + targetIndex;
ASSERTOPENGL(texobj->texture.map.texobjs.name == 0,
"Non-default texture\n");
gc->texture.texture[targetIndex] = &(texobj->texture);
*pBoundTexture = texobj;
pts->texobjs = texobj->texture.map.texobjs;
pts->params = texobj->texture.map.params;
/* Need to reset the current texture and such. */
__GL_DELAY_VALIDATE(gc);
break;
}
}
if (textures[i] != rangeVal) {
/* delete up to this one */
__glNamesDeleteRange(gc,array,start,rangeVal-start);
start = rangeVal = textures[i];
}
}
__glNamesDeleteRange(gc,array,start,rangeVal-start);
}
// These macros used for comparing properties of 2 textures
#define _DIFFERENT_TEX_PARAMS( tex1, tex2 ) \
( ! RtlEqualMemory( &(tex1)->params, &(tex2)->params, sizeof(__GLtextureParamState)) )
#define _DIFFERENT_TEXDATA_FORMATS( tex1, tex2 ) \
( (tex1)->level[0].internalFormat != (tex2)->level[0].internalFormat )
/*
** This routine is used by the pick routines to actually perform
** the bind.
*/
void FASTCALL __glBindTexture(__GLcontext *gc, GLuint targetIndex,
GLuint texture, GLboolean callGen)
{
__GLtextureObject *texobj;
ASSERTOPENGL(NULL != gc->texture.shared->namesArray,
"No texture names array\n");
// Check if this texture is the currently bound one
if( (targetIndex != __GL_TEX_TARGET_INDEX_DDRAW &&
gc->texture.boundTextures[targetIndex] != &gc->texture.ddtex.texobj &&
texture == gc->texture.boundTextures[targetIndex]->
texture.map.texobjs.name) ||
(targetIndex == __GL_TEX_TARGET_INDEX_DDRAW &&
gc->texture.boundTextures[__GL_TEX_TARGET_INDEX_2D] ==
&gc->texture.ddtex.texobj))
{
return;
}
/*
** Retrieve the texture object from the namesArray structure.
*/
if (targetIndex == __GL_TEX_TARGET_INDEX_DDRAW)
{
targetIndex = __GL_TEX_TARGET_INDEX_2D;
texobj = &gc->texture.ddtex.texobj;
}
else if (texture == 0)
{
texobj = gc->texture.defaultTextures + targetIndex;
ASSERTOPENGL(NULL != texobj, "No default texture\n");
ASSERTOPENGL(texobj->texture.map.texobjs.name == 0,
"Non-default texture\n");
}
else
{
texobj = (__GLtextureObject *)
__glNamesLockData(gc, gc->texture.shared->namesArray, texture);
}
/*
** Is this the first time this name has been bound?
** If so, create a new texture object and initialize it.
*/
if (NULL == texobj) {
texobj = (__GLtextureObject *)GCALLOCZ(gc, sizeof(*texobj));
if (texobj == NULL)
{
return;
}
if (!__glInitTextureObject(gc, texobj, texture, targetIndex))
{
GCFREE(gc, texobj);
return;
}
__glInitTextureMachine(gc, targetIndex, &(texobj->texture), GL_TRUE);
__glNamesNewData(gc, gc->texture.shared->namesArray, texture, texobj);
/*
** Shortcut way to lock without doing another lookup.
*/
__glNamesLockArray(gc, gc->texture.shared->namesArray);
texobj->refcount++;
__glNamesUnlockArray(gc, gc->texture.shared->namesArray);
__glTexPriListAdd(gc, texobj, GL_TRUE);
}
else {
/*
** Retrieved an existing texture object. Do some
** sanity checks.
*/
if (texobj->targetIndex != targetIndex) {
__glSetError(GL_INVALID_OPERATION);
return;
}
ASSERTOPENGL(texture == texobj->texture.map.texobjs.name,
"Texture name mismatch\n");
}
{
__GLperTextureState *pts;
__GLtexture *ptm;
__GLtextureObject *boundTexture;
pts = &(gc->state.texture.texture[targetIndex]);
ptm = &(gc->texture.texture[targetIndex]->map);
boundTexture = gc->texture.boundTextures[targetIndex];
/* Copy the current stackable state into the bound texture. */
ptm->params = pts->params;
ptm->texobjs = pts->texobjs;
// If the DDraw texture is currently bound, release its
// resources
if (boundTexture == &gc->texture.ddtex.texobj)
{
glsrvUnbindDirectDrawTexture(gc);
}
else if (boundTexture->texture.map.texobjs.name != 0)
{
/* Unlock the texture that is being unbound. */
__glNamesUnlockData(gc, boundTexture, __glCleanupTexObj);
}
/*
** Install the new texture into the correct target and save
** its pointer so it can be unlocked easily when it is unbound.
*/
gc->texture.texture[targetIndex] = &(texobj->texture);
gc->texture.boundTextures[targetIndex] = texobj;
/* Copy the new texture's stackable state into the context state. */
pts->params = texobj->texture.map.params;
pts->texobjs = texobj->texture.map.texobjs;
if (callGen)
{
__glGenMakeTextureCurrent(gc, &texobj->texture.map,
texobj->loadKey);
}
__GL_DELAY_VALIDATE_MASK( gc, __GL_DIRTY_TEXTURE );
// We can avoid dirtying generic if the new texture has same
// properties as the old one...
if( !( gc->dirtyMask & __GL_DIRTY_GENERIC ) )
{
// GL_DIRTY_GENERIC has not yet been set
__GLtexture *newTex = &texobj->texture.map;
__GLtexture *oldTex = &boundTexture->texture.map;
if( (_DIFFERENT_TEX_PARAMS( newTex, oldTex )) ||
(_DIFFERENT_TEXDATA_FORMATS( newTex, oldTex )) ||
(texobj->targetIndex != boundTexture->targetIndex) )
{
__GL_DELAY_VALIDATE( gc ); // dirty generic
}
}
}
}
GLvoid APIPRIVATE __glim_BindTexture(GLenum target, GLuint texture)
{
GLuint targetIndex;
/*
** Need to validate in case a new texture was popped into
** the state immediately prior to this call.
*/
__GL_SETUP_NOT_IN_BEGIN_VALIDATE();
switch (target) {
case GL_TEXTURE_1D:
targetIndex = 2;
break;
case GL_TEXTURE_2D:
targetIndex = 3;
break;
default:
__glSetError(GL_INVALID_ENUM);
return;
}
__glBindTexture(gc, targetIndex, texture, GL_TRUE);
}
#ifdef GL_WIN_multiple_textures
void APIPRIVATE __glim_BindNthTextureWIN(GLuint index, GLenum target, GLuint texture)
{
}
#endif // GL_WIN_multiple_textures
GLvoid APIPRIVATE __glim_PrioritizeTextures(GLsizei n,
const GLuint* textures,
const GLclampf* priorities)
{
int i;
__GLtextureObject *texobj;
GLuint targetIndex;
__GLtextureObject **pBoundTexture;
GLclampf priority;
__GL_SETUP_NOT_IN_BEGIN();
__GL_CHECK_VALID_N_PARAM(return);
for (i=0; i < n; i++) {
/* silently ignore default texture */
if (0 == textures[i]) continue;
texobj = (__GLtextureObject *)
__glNamesLockData(gc, gc->texture.shared->namesArray, textures[i]);
/* silently ignore non-texture */
if (NULL == texobj) continue;
priority = __glClampf(priorities[i], __glZero, __glOne);
texobj->texture.map.texobjs.priority = priority;
// If this texture is currently bound, also update the
// copy of the priority in the gc's state
// Keeping copies is not a good design. This
// should be improved
for (targetIndex = 0, pBoundTexture = gc->texture.boundTextures;
targetIndex < (GLuint)gc->constants.numberOfTextures;
targetIndex++, pBoundTexture++)
{
/* Is the texture currently bound? */
if (*pBoundTexture != &gc->texture.ddtex.texobj &&
(*pBoundTexture)->texture.map.texobjs.name == textures[i])
{
gc->state.texture.texture[targetIndex].texobjs.priority =
priority;
break;
}
}
__glTexPriListChangePriority(gc, texobj, GL_FALSE);
__glNamesUnlockData(gc, texobj, __glCleanupTexObj);
}
__glNamesLockArray(gc, gc->texture.shared->namesArray);
__glTexPriListRealize(gc);
__glNamesUnlockArray(gc, gc->texture.shared->namesArray);
}
GLboolean APIPRIVATE __glim_AreTexturesResident(GLsizei n,
const GLuint* textures,
GLboolean* residences)
{
int i;
__GLtextureObject *texobj;
GLboolean allResident = GL_TRUE;
GLboolean currentResident;
__GL_SETUP_NOT_IN_BEGIN2();
__GL_CHECK_VALID_N_PARAM(return GL_FALSE);
for (i=0; i < n; i++) {
/* Can't query a default texture. */
if (0 == textures[i]) {
__glSetError(GL_INVALID_VALUE);
return GL_FALSE;
}
texobj = (__GLtextureObject *)
__glNamesLockData(gc, gc->texture.shared->namesArray, textures[i]);
/*
** Ensure that all of the names have corresponding textures.
*/
if (NULL == texobj) {
__glSetError(GL_INVALID_VALUE);
return GL_FALSE;
}
if (((__GLGENcontext *)gc)->pMcdState && texobj->loadKey) {
currentResident = ((GenMcdTextureStatus((__GLGENcontext *)gc, texobj->loadKey) & MCDRV_TEXTURE_RESIDENT) != 0);
} else
currentResident = texobj->resident;
if (!currentResident) {
allResident = GL_FALSE;
}
residences[i] = currentResident;
__glNamesUnlockData(gc, texobj, __glCleanupTexObj);
}
return allResident;
}
GLboolean APIPRIVATE __glim_IsTexture(GLuint texture)
{
__GLtextureObject *texobj;
__GL_SETUP_NOT_IN_BEGIN2();
if (0 == texture) return GL_FALSE;
texobj = (__GLtextureObject *)
__glNamesLockData(gc, gc->texture.shared->namesArray, texture);
if (texobj != NULL)
{
__glNamesUnlockData(gc, texobj, __glCleanupTexObj);
return GL_TRUE;
}
return GL_FALSE;
}
#ifdef NT
GLboolean FASTCALL __glCanShareTextures(__GLcontext *gc, __GLcontext *shareMe)
{
GLboolean canShare = GL_TRUE;
if (gc->texture.shared != NULL)
{
__glNamesLockArray(gc, gc->texture.shared->namesArray);
// Make sure we're not trying to replace a shared object
// The spec also says that it is illegal for the new context
// to have any textures
canShare = gc->texture.shared->namesArray->refcount == 1 &&
gc->texture.shared->namesArray->tree == NULL;
__glNamesUnlockArray(gc, gc->texture.shared->namesArray);
}
return canShare;
}
void FASTCALL __glShareTextures(__GLcontext *gc, __GLcontext *shareMe)
{
GLint i, numTextures;
if (gc->texture.shared != NULL)
{
// We know that the names array doesn't have any contents
// so no texture names can be selected as the current texture
// or anything else. Therefore it is safe to simply free
// our array
__glFreeSharedTextureState(gc);
}
__glNamesLockArray(gc, shareMe->texture.shared->namesArray);
gc->texture.shared = shareMe->texture.shared;
gc->texture.shared->namesArray->refcount++;
// Add the new sharer's default textures to the priority list
numTextures = gc->constants.numberOfTextures;
for (i = 0; i < numTextures; i++)
{
__glTexPriListAddToList(gc, gc->texture.defaultTextures+i);
}
// No realization of priority list because these contexts aren't
// current
DBGLEVEL3(LEVEL_INFO, "Sharing textures %p with %p, count %d\n",
gc, shareMe, gc->texture.shared->namesArray->refcount);
__glNamesUnlockArray(gc, shareMe->texture.shared->namesArray);
}
#endif
/******************************Public*Routine******************************\
*
* glsrvBindDirectDrawTexture
*
* Make the DirectDraw texture data in gc->texture the current 2D texture
*
* History:
* Wed Sep 04 11:35:59 1996 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
BOOL APIENTRY glsrvBindDirectDrawTexture(__GLcontext *gc,
int levels,
LPDIRECTDRAWSURFACE *apdds,
DDSURFACEDESC *pddsd,
ULONG flags)
{
__GLmipMapLevel *lev;
__GLtexture *tex;
GLint levIndex;
GLint width, height;
GLint wlog2, hlog2;
__GLddrawTexture *pddtex;
ASSERTOPENGL(levels <= gc->constants.maxMipMapLevel,
"Too many levels in DDraw texture\n");
// Bind the fake DDraw texture.
__glBindTexture(gc, __GL_TEX_TARGET_INDEX_DDRAW, __GL_TEX_DDRAW, GL_FALSE);
pddtex = &gc->texture.ddtex;
tex = &pddtex->texobj.texture.map;
pddtex->levels = levels;
memcpy(gc->texture.ddtex.pdds, apdds, levels*sizeof(LPDIRECTDRAWSURFACE));
pddtex->gdds.pdds = apdds[0];
pddtex->gdds.ddsd = *pddsd;
pddtex->gdds.dwBitDepth =
DdPixDepthToCount(pddsd->ddpfPixelFormat.dwRGBBitCount);
pddtex->flags = flags;
// Fill out the DirectDraw texture data
width = (GLint)pddtex->gdds.ddsd.dwWidth;
wlog2 = __glIntLog2(width);
height = (GLint)pddtex->gdds.ddsd.dwHeight;
hlog2 = __glIntLog2(height);
if (wlog2 > hlog2)
{
tex->p = wlog2;
}
else
{
tex->p = hlog2;
}
lev = tex->level;
for (levIndex = 0; levIndex < gc->texture.ddtex.levels; levIndex++)
{
// Buffer pointer is filled in at attention time.
// If we're going to pass this texture to the MCD then we
// fill in the surface handles at this time so they're
// given to the driver at create time.
if (flags & DDTEX_VIDEO_MEMORY)
{
lev->buffer = (__GLtextureBuffer *)
((LPDDRAWI_DDRAWSURFACE_INT)apdds[levIndex])->
lpLcl->hDDSurface;
}
else
{
lev->buffer = NULL;
}
lev->width = width;
lev->height = height;
lev->width2 = width;
lev->height2 = height;
lev->width2f = (__GLfloat)width;
lev->height2f = (__GLfloat)height;
lev->widthLog2 = wlog2;
lev->heightLog2 = hlog2;
lev->border = 0;
lev->luminanceSize = 0;
lev->intensitySize = 0;
if (pddtex->gdds.ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8)
{
lev->requestedFormat = tex->paletteRequestedFormat;
lev->baseFormat = tex->paletteBaseFormat;
lev->internalFormat = GL_COLOR_INDEX8_EXT;
__glSetPaletteLevelExtract8(tex, lev, 0);
lev->redSize = 0;
lev->greenSize = 0;
lev->blueSize = 0;
lev->alphaSize = 0;
}
else
{
if (pddtex->gdds.ddsd.ddsCaps.dwCaps & DDSCAPS_ALPHA)
{
lev->requestedFormat = GL_RGBA;
lev->baseFormat = GL_RGBA;
}
else
{
lev->requestedFormat = GL_RGB;
lev->baseFormat = GL_RGB;
}
lev->internalFormat = GL_BGRA_EXT;
lev->extract = __glExtractTexelBGRA8;
lev->redSize = 8;
lev->greenSize = 8;
lev->blueSize = 8;
lev->alphaSize = 8;
}
if (width != 1)
{
width >>= 1;
wlog2--;
}
if (height != 1)
{
height >>= 1;
hlog2--;
}
lev++;
}
// If the texture is in VRAM then attempt to create an MCD handle for it.
// This must be done before palette operations so that
// the loadKey is set.
if (flags & DDTEX_VIDEO_MEMORY)
{
pddtex->texobj.loadKey =
__glGenLoadTexture(gc, tex, MCDTEXTURE_DIRECTDRAW_SURFACES);
// Remove handles that were set earlier.
lev = tex->level;
for (levIndex = 0; levIndex < gc->texture.ddtex.levels; levIndex++)
{
lev->buffer = NULL;
lev++;
}
}
else
{
pddtex->texobj.loadKey = 0;
}
// Pick up palette for paletted surface
if (pddtex->gdds.ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8)
{
LPDIRECTDRAWPALETTE pddp;
HRESULT hr;
hr = pddtex->gdds.pdds->lpVtbl->
GetPalette(pddtex->gdds.pdds, &pddp);
if (hr == DD_OK && pddp != NULL)
{
PALETTEENTRY pe[256];
if (pddp->lpVtbl->GetEntries(pddp, 0, 0, 256, pe) == DD_OK)
{
__glim_ColorTableEXT(GL_TEXTURE_2D, GL_RGB,
256, GL_RGBA, GL_UNSIGNED_BYTE,
pe, GL_FALSE);
}
pddp->lpVtbl->Release(pddp);
}
}
// If we have a loadKey, make the texture current
if (pddtex->texobj.loadKey != 0)
{
__glGenMakeTextureCurrent(gc, tex, pddtex->texobj.loadKey);
}
__GL_DELAY_VALIDATE(gc);
return TRUE;
}
/******************************Public*Routine******************************\
*
* glsrvUnbindDirectDrawTexture
*
* Cleans up DirectDraw texture data
*
* History:
* Wed Sep 04 13:45:08 1996 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
void APIENTRY glsrvUnbindDirectDrawTexture(__GLcontext *gc)
{
GLint i;
__GLddrawTexture *pddtex;
__GLGENcontext *gengc = (__GLGENcontext *)gc;
pddtex = &gc->texture.ddtex;
// Make sure a texture is bound
if (pddtex->levels <= 0)
{
return;
}
// Delete any MCD information
if (pddtex->texobj.loadKey != 0)
{
__glGenFreeTexture(gc, &pddtex->texobj.texture.map,
pddtex->texobj.loadKey);
pddtex->texobj.loadKey = 0;
}
for (i = 0; i < pddtex->levels; i++)
{
// If we're currently in an attention then we locked the texture
// surfaces and need to unlock them before we release them.
//
// Since there's no way to bind new DD textures in a batch, we
// are guaranteed to have had the texture active at the beginning
// of the batch and therefore we're guaranteed to have the texture
// locks.
if (gengc->fsLocks & LOCKFLAG_DD_TEXTURE)
{
DDSUNLOCK(pddtex->pdds[i],
pddtex->texobj.texture.map.level[i].buffer);
#if DBG
pddtex->texobj.texture.map.level[i].buffer = NULL;
#endif
}
pddtex->pdds[i]->lpVtbl->
Release(pddtex->pdds[i]);
#if DBG
pddtex->pdds[i] = NULL;
#endif
}
#if DBG
memset(&pddtex->gdds, 0, sizeof(pddtex->gdds));
#endif
pddtex->levels = 0;
if (gengc->fsGenLocks & LOCKFLAG_DD_TEXTURE)
{
gengc->fsGenLocks &= ~LOCKFLAG_DD_TEXTURE;
gengc->fsLocks &= ~LOCKFLAG_DD_TEXTURE;
}
__GL_DELAY_VALIDATE(gc);
}