552 lines
14 KiB
C
552 lines
14 KiB
C
/*
|
|
* Copyright (c) 1993-1995 Argonaut Technologies Limited. All rights reserved.
|
|
*
|
|
* $Id: sbuffer.c 2.1 1996/03/15 17:25:02 sam Exp $
|
|
* $Locker: $
|
|
*
|
|
* Stored buffer methods for S3 VirGE
|
|
*
|
|
*/
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <windows.h>
|
|
#include <ddraw.h>
|
|
|
|
#include "drv.h"
|
|
#include "shortcut.h"
|
|
#include "brassert.h"
|
|
|
|
BR_RCS_ID("$Id: sbuffer.c 2.1 1996/03/15 17:25:02 sam Exp $");
|
|
|
|
/* Default dispatch table for primitive state (defined at end of file) */
|
|
static struct br_buffer_stored_dispatch bufferStoredDispatch;
|
|
|
|
|
|
/* External routines to allow us to find out if a pixelmap is a real device pixelmap or not */
|
|
extern br_boolean CheckFrontPixelmapDispatch(void *address);
|
|
extern br_boolean CheckBackPixelmapDispatch(void *address);
|
|
|
|
|
|
/*
|
|
* Primitive state info. template
|
|
*/
|
|
#define F(f) offsetof(struct br_buffer_stored, f)
|
|
|
|
static struct br_tv_template_entry bufferStoredTemplateEntries[] = {
|
|
{BRT_IDENTIFIER_CSTR, 0, F(identifier), BRTV_QUERY | BRTV_ALL, BRTV_CONV_COPY, },
|
|
};
|
|
#undef F
|
|
|
|
static struct br_tv_template bufferStoredTemplate = {
|
|
BR_ASIZE(bufferStoredTemplateEntries),
|
|
bufferStoredTemplateEntries
|
|
};
|
|
|
|
|
|
void ClearSbufferTemplates(void)
|
|
{
|
|
CLEAR_TEMPLATE(bufferStored);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* This is the default palette used for paletted textures with no palette data attached
|
|
* It is used to convert them to 15 bit textures for true colour video modes
|
|
* Set in devclut.c
|
|
*/
|
|
br_colour S3_default_palette[256];
|
|
|
|
/* This is the flag used to decide what the driver behaviour is with 8 bit textures
|
|
* it is set in devpixmp.c when the front surface is created */
|
|
|
|
extern br_boolean S3_convert_8bit_to_15;
|
|
|
|
|
|
/* Macro for 24 bit to 15 bit colour conversion */
|
|
#define CONV24TO15(a) ((a & 0xFF)>>3) | ((a & 0xF800) >> 6) | ((a & 0xF80000) >> 9)
|
|
|
|
/* Spammy little routine to get the format of an S3 surface */
|
|
|
|
br_uint_32 GetS3Format(br_device_pixelmap *pm)
|
|
{
|
|
switch(pm->pm_type)
|
|
{
|
|
case BR_PMT_INDEX_8:
|
|
return(S3DTK_TEXPALETTIZED8);
|
|
case BR_PMT_RGB_555:
|
|
return(S3DTK_TEXARGB1555);
|
|
case BR_PMT_RGBX_888:
|
|
case BR_PMT_RGBA_8888:
|
|
return(S3DTK_TEXARGB8888);
|
|
case BR_PMT_RGBA_4444:
|
|
return(S3DTK_TEXARGB4444);
|
|
default:
|
|
return(S3DTK_TEXPALETTIZED8);
|
|
}
|
|
}
|
|
|
|
|
|
/* Routine used to convert an 8 bit pixelmap into a 15 bit render buffer
|
|
* If create_alpha is TRUE then the top bit of the data will be used for a 1 bit alpha mask.
|
|
* and any texels in colour 0 will be transparent. Otherwise the top bit of all texels will
|
|
* be 0 */
|
|
|
|
br_boolean S3Convert8To15(br_device_pixelmap *pm,
|
|
struct render_buffer *rb,
|
|
br_buffer_stored *self,
|
|
br_boolean has_palette,
|
|
br_boolean create_alpha)
|
|
{
|
|
br_uint_16 *new_pixel=NULL;
|
|
br_uint_8 *old_pixel;
|
|
br_colour *palette;
|
|
br_uint_32 num_locations;
|
|
br_uint_32 i;
|
|
|
|
num_locations = pm->pm_width * pm->pm_height;
|
|
|
|
if(has_palette)
|
|
palette = pm->pm_map->pixels;
|
|
else
|
|
palette = &(S3_default_palette[0]);
|
|
|
|
/* Converted pixels are a child resource of the stored buffer */
|
|
new_pixel = BrResAllocate(self,
|
|
num_locations*sizeof(br_uint_16),
|
|
BR_MEMORY_SCRATCH);
|
|
if(!new_pixel)
|
|
return(BR_FALSE);
|
|
|
|
/* Now do the conversion */
|
|
rb->base_mem = new_pixel;
|
|
old_pixel = pm->pm_pixels;
|
|
|
|
for(i=0;i<num_locations;i++,new_pixel++,old_pixel++)
|
|
{
|
|
*new_pixel = CONV24TO15(palette[*old_pixel]);
|
|
if(create_alpha)
|
|
{
|
|
if(*old_pixel == 0) /* Palette (0) is transparent (Alpha Mask) */
|
|
*new_pixel &= 0x7FFF; /* Clear Alpha bit */
|
|
else
|
|
*new_pixel |= 0x8000;
|
|
}
|
|
}
|
|
|
|
rb->type = BR_PMT_RGB_555;
|
|
if(CheckFrontPixelmapDispatch(pm->dispatch) || CheckBackPixelmapDispatch(pm->dispatch))
|
|
rb->s3_surface = pm->s3_surface;
|
|
else
|
|
{
|
|
rb->s3_surface.sfWidth = pm->pm_width;
|
|
rb->s3_surface.sfHeight = pm->pm_height;
|
|
}
|
|
|
|
rb->s3_surface.sfFormat = S3DTK_TEXARGB1555;
|
|
|
|
rb->s3_surface.sfOffset = rb->base_mem;
|
|
rb->bpp = 2;
|
|
rb->width_b = pm->pm_width * 2;
|
|
rb->width_p = pm->pm_width;
|
|
rb->height = pm->pm_height;
|
|
rb->stride = pm->pm_row_bytes * 2;
|
|
rb->size = rb->width_b * rb->height;
|
|
rb->base = (br_uint_8 *)(rb->base_mem)+
|
|
pm->pm_base_y * rb->stride +
|
|
pm->pm_base_x * rb->bpp;
|
|
|
|
rb->sel = NULL;
|
|
|
|
rb->mip_offset = 0 ; /* I'm not allowing mipmapped 8 bit textures. */
|
|
|
|
|
|
return(BR_TRUE);
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
* Build a render_buffer structure from a pixelmap - used to create texture maps and
|
|
* outputs (screen and Z). If it is being called to set up a texture map then the
|
|
* texture flag will be BR_TRUE, and additional processing is carried out for alpha
|
|
* channel and palette processing
|
|
*/
|
|
br_error S3SetupRenderBuffer(struct render_buffer *rb,
|
|
br_device_pixelmap *pm,
|
|
br_buffer_stored *self,
|
|
br_boolean texture)
|
|
{
|
|
br_boolean need_convert = BR_FALSE;
|
|
int bpp = 1;
|
|
br_boolean device_pm = BR_FALSE;
|
|
|
|
switch(pm->pm_type)
|
|
{
|
|
case BR_PMT_INDEX_8:
|
|
bpp = 1;
|
|
need_convert = BR_TRUE;
|
|
break;
|
|
case BR_PMT_RGB_555:
|
|
case BR_PMT_RGB_565:
|
|
case BR_PMT_DEPTH_16:
|
|
case BR_PMT_RGBA_4444:
|
|
bpp = 2;
|
|
break;
|
|
|
|
case BR_PMT_RGB_888:
|
|
bpp = 3;
|
|
break;
|
|
|
|
case BR_PMT_RGBX_888:
|
|
case BR_PMT_RGBA_8888:
|
|
bpp = 4;
|
|
break;
|
|
}
|
|
|
|
/* Find out if this is a device pixelmap */
|
|
device_pm = CheckFrontPixelmapDispatch(pm->dispatch) || CheckBackPixelmapDispatch(pm->dispatch);
|
|
|
|
rb->type = pm->pm_type;
|
|
rb->bpp = bpp;
|
|
rb->width_b = pm->pm_width * bpp;
|
|
rb->width_p = pm->pm_width;
|
|
rb->height = pm->pm_height;
|
|
rb->stride = pm->pm_row_bytes;
|
|
rb->size = pm->pm_height * pm->pm_row_bytes;
|
|
|
|
/* If this is a device pixelmap then we must lock and unlock it to get the correct pointer
|
|
* for the base of the pixel data */
|
|
if(device_pm)
|
|
{
|
|
if(S3Lock(pm->surface, &pm->pm_pixels, NULL, NULL))
|
|
{
|
|
/* Memory base pointer */
|
|
rb->base_mem = pm->pm_pixels;
|
|
/* 0,0 pixel/texel */
|
|
rb->base = (br_uint_8 *)(pm->pm_pixels)+
|
|
pm->pm_base_y * pm->pm_row_bytes +
|
|
pm->pm_base_x * bpp;
|
|
S3Unlock(pm->surface,pm->pm_pixels);
|
|
}
|
|
else
|
|
{
|
|
rb->base_mem = pm->pm_pixels;
|
|
/* 0,0 pixel/texel */
|
|
rb->base = (br_uint_8 *)(pm->pm_pixels)+
|
|
pm->pm_base_y * pm->pm_row_bytes +
|
|
pm->pm_base_x * bpp;
|
|
return(BRE_DEV_LOCK_FAIL);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Memory base pointer */
|
|
rb->base_mem = pm->pm_pixels;
|
|
/* 0,0 pixel/texel */
|
|
rb->base = (br_uint_8 *)(pm->pm_pixels)+
|
|
pm->pm_base_y * pm->pm_row_bytes +
|
|
pm->pm_base_x * bpp;
|
|
}
|
|
|
|
rb->sel = (br_uint_16)pm->pm_pixels_qualifier;
|
|
|
|
|
|
rb->mip_offset = (br_uint_16)pm->pm_mip_offset;
|
|
|
|
/* We must discover if this is a device pixelmap so that we know if the S3
|
|
* pixelmap fields are valid. The only way I know to do this is to see if its
|
|
* dispatch table pointer matches that for device pixelmaps */
|
|
if(device_pm)
|
|
{
|
|
/* Copy the data from the parent pixelmap */
|
|
rb->s3_surface = pm->s3_surface;
|
|
if(pm->video_memory)
|
|
rb->s3_surface.sfFormat |= S3DTK_VIDEO;
|
|
/* Set the render buffer field to reflect the location of the parent buffer */
|
|
rb->always_in_video_memory = pm->video_memory;
|
|
if(rb->always_in_video_memory == BR_TRUE)
|
|
rb->in_video_memory = BR_TRUE;
|
|
}
|
|
else
|
|
{
|
|
/* Create the appropriate data */
|
|
rb->s3_surface.sfWidth = pm->pm_width;
|
|
rb->s3_surface.sfHeight = pm->pm_height;
|
|
rb->s3_surface.sfOffset = pm->pm_pixels;
|
|
rb->s3_surface.sfFormat = GetS3Format(pm);
|
|
/* Non device pixelmaps are always in system memory */
|
|
rb->always_in_video_memory = BR_FALSE;
|
|
}
|
|
|
|
|
|
/* Only do the following for texture buffers, not output buffers.
|
|
* NOTE! buffers allocated in video memory by a match operation _cannot_
|
|
* be colour converted */
|
|
if((texture == BR_TRUE) && (rb->always_in_video_memory == BR_FALSE))
|
|
{
|
|
/* First convert the texture from 8 to 15 bit if required
|
|
* S3_convert_8bit_to_15 is set when the main device pixelmap is created in
|
|
* a true colour output mode */
|
|
if(S3_convert_8bit_to_15 == BR_TRUE)
|
|
{
|
|
/* If we have a paletted texture and are in a true colour video mode
|
|
* then we must convert it to a 15 bit equivalent for the purposes of
|
|
* the S3 (no paletted texture support in true colour modes).*/
|
|
if(need_convert == BR_TRUE)
|
|
{
|
|
if(self)
|
|
{
|
|
if(pm->pm_map)
|
|
{
|
|
if(!S3Convert8To15(pm,rb,self,BR_TRUE,BR_TRUE))
|
|
return(BRE_FAIL);
|
|
}
|
|
else
|
|
{
|
|
if(!S3Convert8To15(pm,rb,self,BR_FALSE,BR_TRUE))
|
|
return(BRE_FAIL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Check the texture map out to see if it contains valid alpha channel information */
|
|
rb->alpha_pixels = BR_FALSE; /* default to off */
|
|
|
|
/* RGBA_8888 and 4444 texture maps should always have a valid alpha channel */
|
|
if((rb->type == BR_PMT_RGBA_8888) || (rb->type == BR_PMT_RGBA_4444))
|
|
rb->alpha_pixels = BR_TRUE;
|
|
|
|
/* RGB_555 textures _may_ have alpha information in the high bit. This is the time
|
|
* consuming part - we must check through the texture map. If the high bit of any
|
|
* 16 bit word differs from the high bit of the first 16 bit word (pay attention now!),
|
|
* then we assume that the texture map contains an alpha channel and flag it as such. */
|
|
if(rb->type == BR_PMT_RGB_555)
|
|
{
|
|
/* Must use 16 bit pointers for this method */
|
|
br_uint_16 *current_texels;
|
|
br_uint_16 *endptr;
|
|
|
|
endptr = (br_uint_16*)(rb->base_mem);
|
|
endptr += (rb->width_p * rb->height);
|
|
|
|
current_texels = (br_uint_16*)rb->base_mem;
|
|
if(*current_texels & 0x8000)
|
|
{
|
|
/* First texel has high bit set - scan for ones with high bit cleared */
|
|
for(current_texels = (br_uint_16*)rb->base_mem;
|
|
current_texels < endptr;
|
|
current_texels++)
|
|
{
|
|
if(!(*current_texels & 0x8000))
|
|
{
|
|
rb->alpha_pixels = BR_TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* First texel has high bit cleared - scan for ones with high bit set */
|
|
for(current_texels = (br_uint_16*)rb->base_mem;
|
|
current_texels < endptr;
|
|
current_texels++)
|
|
{
|
|
if(*current_texels & 0x8000)
|
|
{
|
|
rb->alpha_pixels = BR_TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Make sure that the surface is flagged as a texture if that is its use */
|
|
if(texture == BR_TRUE)
|
|
rb->s3_surface.sfFormat |= S3DTK_TEXTURE;
|
|
else
|
|
rb->s3_surface.sfFormat &= ~S3DTK_TEXTURE;
|
|
|
|
#if 0
|
|
/* If the texture dimensions differ by >= 128 then mark as uncacheable */
|
|
if(texture == BR_TRUE)
|
|
{
|
|
if(abs(rb->width_p - rb->height) >= 128)
|
|
rb->uncacheable = BR_TRUE;
|
|
}
|
|
#endif
|
|
|
|
return(BRE_OK);
|
|
|
|
}
|
|
|
|
/*
|
|
* Set up a static device object
|
|
*/
|
|
struct br_buffer_stored * BufferStoredHardS3Allocate(struct br_primitive_library *plib,
|
|
br_token use, struct br_device_pixelmap *pm, br_token_value *tv)
|
|
{
|
|
struct br_buffer_stored * self;
|
|
char *ident;
|
|
br_error r;
|
|
|
|
switch(use) {
|
|
case BRT_TEXTURE_O:
|
|
case BRT_COLOUR_MAP_O:
|
|
ident ="Colour-Map";
|
|
break;
|
|
case BRT_INDEX_SHADE_O:
|
|
ident ="Shade-Table";
|
|
break;
|
|
case BRT_INDEX_BLEND_O:
|
|
ident ="Blend-Table";
|
|
break;
|
|
case BRT_SCREEN_DOOR_O:
|
|
ident ="Screendoor-Table";
|
|
break;
|
|
case BRT_INDEX_LIGHT_O:
|
|
ident ="Lighting-Table";
|
|
break;
|
|
case BRT_BUMP_O:
|
|
ident ="Bump-Map";
|
|
break;
|
|
default:
|
|
return NULL;
|
|
}
|
|
|
|
self = BrResAllocate(DRIVER_RESOURCE, sizeof(*self), BR_MEMORY_OBJECT);
|
|
|
|
if(self == NULL)
|
|
return NULL;
|
|
|
|
self->dispatch = &bufferStoredDispatch;
|
|
self->identifier = ident;
|
|
|
|
/*
|
|
* If caller does not guarantee to keep source data around, or
|
|
* source data is not memory mapped, then clone an in-memory copy
|
|
*/
|
|
|
|
self->flags |= SBUFF_SHARED;
|
|
|
|
r = S3SetupRenderBuffer(&self->buffer, pm, self,BR_TRUE);
|
|
|
|
if(r != BRE_OK)
|
|
{
|
|
BrResFree(self);
|
|
return(NULL);
|
|
}
|
|
|
|
self->plib = plib;
|
|
|
|
ObjectContainerAddFront(plib,(br_object*)self);
|
|
|
|
return self;
|
|
}
|
|
|
|
|
|
/* If a buffer is updated that is a current input buffer we must
|
|
* force a reload (and possibly a re-conversion)of the texture map */
|
|
|
|
static br_error BR_CMETHOD_DECL(br_buffer_stored_hardS3, update)(
|
|
struct br_buffer_stored *self,
|
|
struct br_device_pixelmap *pm,
|
|
br_token_value *tv)
|
|
{
|
|
br_error r;
|
|
|
|
/* Unpack any hints */
|
|
if(self->flags & SBUFF_SHARED)
|
|
{
|
|
if(S3_convert_8bit_to_15 == BR_TRUE)
|
|
{
|
|
/* If we have a paletted texture then we must convert it to a 15 bit equivalent
|
|
* for the purposes of the S3 (no paletted texture support) */
|
|
if(pm->pm_type == BR_PMT_INDEX_8)
|
|
{
|
|
/* Free the converted pixels pointer in the render buffer IF this is not a video memory pixelmap.
|
|
* If it is _only_ located in video memory then we do not have jurisdiction over the data
|
|
* so we cannot either convert or free data associated with this buffer */
|
|
if((self->buffer.base_mem)&&(self->buffer.always_in_video_memory == BR_FALSE))
|
|
{
|
|
BrResFree(self->buffer.base_mem);
|
|
self->buffer.base = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Set up the new render buffer */
|
|
r = S3SetupRenderBuffer(&self->buffer,pm,self,BR_TRUE);
|
|
if(r != BRE_OK)
|
|
return(r);
|
|
}
|
|
|
|
self->buffer_updated = BR_TRUE;
|
|
|
|
return(BRE_OK);
|
|
}
|
|
|
|
|
|
|
|
/* If a buffer is freed then we must make sure that its ghost does not */
|
|
/* come back to haunt us */
|
|
/* ie if it is the current texture buffer then we must force the current */
|
|
/* buffer to NULL */
|
|
|
|
static void BR_CMETHOD_DECL(br_buffer_stored_hardS3, free)(br_buffer_stored *self)
|
|
{
|
|
S3LoseRenderBuffer(&self->buffer);
|
|
ObjectContainerRemove(self->plib,(br_object*)self);
|
|
BrResFreeNoCallback(self);
|
|
}
|
|
|
|
static br_token BR_CMETHOD_DECL(br_buffer_stored_hardS3, type)(br_buffer_stored *self)
|
|
{
|
|
return BRT_BUFFER_STORED;
|
|
}
|
|
|
|
static br_boolean BR_CMETHOD_DECL(br_buffer_stored_hardS3, isType)(br_buffer_stored *self, br_token t)
|
|
{
|
|
return (t == BRT_BUFFER_STORED) || (t == BRT_OBJECT);
|
|
}
|
|
|
|
static br_int_32 BR_CMETHOD_DECL(br_buffer_stored_hardS3, space)(br_buffer_stored *self)
|
|
{
|
|
return BrResSizeTotal(self);
|
|
}
|
|
|
|
static struct br_tv_template * BR_CMETHOD_DECL(br_buffer_stored_hardS3,templateQuery)
|
|
(br_buffer_stored *self)
|
|
{
|
|
bufferStoredTemplate.res = DRIVER_RESOURCE;
|
|
return &bufferStoredTemplate;
|
|
}
|
|
|
|
/*
|
|
* Default dispatch table for device
|
|
*/
|
|
static struct br_buffer_stored_dispatch bufferStoredDispatch = {
|
|
NULL,NULL,NULL,NULL,
|
|
BR_CMETHOD_REF(br_buffer_stored_hardS3, free),
|
|
BR_CMETHOD_REF(br_object_s3, identifier),
|
|
BR_CMETHOD_REF(br_buffer_stored_hardS3, type),
|
|
BR_CMETHOD_REF(br_buffer_stored_hardS3, isType),
|
|
BR_CMETHOD_REF(br_object_s3, device),
|
|
BR_CMETHOD_REF(br_buffer_stored_hardS3, space),
|
|
|
|
BR_CMETHOD_REF(br_buffer_stored_hardS3, templateQuery),
|
|
BR_CMETHOD_REF(br_object, query),
|
|
BR_CMETHOD_REF(br_object, queryBuffer),
|
|
BR_CMETHOD_REF(br_object, queryMany),
|
|
BR_CMETHOD_REF(br_object, queryManySize),
|
|
BR_CMETHOD_REF(br_object, queryAll),
|
|
BR_CMETHOD_REF(br_object, queryAllSize),
|
|
|
|
BR_CMETHOD_REF(br_buffer_stored_hardS3, update),
|
|
};
|
|
|
|
|