787 lines
19 KiB
C
787 lines
19 KiB
C
|
/*
|
||
|
* Copyright (c) 1993-1995 Argonaut Technologies Limited. All rights reserved.
|
||
|
*
|
||
|
* Stored buffer methods
|
||
|
*/
|
||
|
#include <stddef.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
#include "texture.h"
|
||
|
|
||
|
#include "drv.h"
|
||
|
#include "shortcut.h"
|
||
|
#include "brassert.h"
|
||
|
#include <host.h>
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
#define USE_TEXTURE_HEAP // MUST not be undefined for DOS version
|
||
|
#define USE_HEAP_FREEING
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Default dispatch table for primitive state (defined at end of file)
|
||
|
*/
|
||
|
static struct br_buffer_stored_dispatch bufferStoredDispatch;
|
||
|
|
||
|
/*
|
||
|
* 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
|
||
|
};
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Translate any tokens passed down to the allocate
|
||
|
*/
|
||
|
struct sbufferAllocate_tokens {
|
||
|
br_uint_32 flags;
|
||
|
};
|
||
|
|
||
|
#define F(f) offsetof(struct sbufferAllocate_tokens, f)
|
||
|
static struct br_tv_template_entry sbufferAllocateTemplateEntries[] = {
|
||
|
{BRT(PREFER_SHARE_B), F(flags), BRTV_SET | BRTV_QUERY | BRTV_ALL, BRTV_CONV_BIT, SBUF_PREFER_SHARE, 1},
|
||
|
};
|
||
|
#undef F
|
||
|
|
||
|
static struct br_tv_template sbufferAllocateTemplate = {
|
||
|
BR_ASIZE(sbufferAllocateTemplateEntries),
|
||
|
sbufferAllocateTemplateEntries
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
void BufferStoredMystClearTemplate(void)
|
||
|
{
|
||
|
CLEAR_TEMPLATE(bufferStored);
|
||
|
CLEAR_TEMPLATE(sbufferAllocate);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Heap memory management
|
||
|
*
|
||
|
* Managed by
|
||
|
*/
|
||
|
struct heap_memory_block_t;
|
||
|
typedef struct heap_memory_block_t heap_memory_block;
|
||
|
struct heap_memory_block_t {
|
||
|
MSImemptr heap; // Which heap is this block in
|
||
|
MSImemptr mem; // Pointer to the memory in the heap
|
||
|
br_uint_32 size; // Memory block size
|
||
|
heap_memory_block *next; // Next block on free list
|
||
|
};
|
||
|
|
||
|
|
||
|
static heap_memory_block *heap_list = NULL;
|
||
|
|
||
|
/* Allocate heap in blocks of this many 4K pages: 256 is 1M blocks */
|
||
|
#define HEAP_BLOCK_PAGES 256
|
||
|
#define MAX_HEAP_OBJECT_SIZE (HEAP_BLOCK_PAGES * 4096)
|
||
|
|
||
|
|
||
|
/*
|
||
|
* No heap memory available; expand the heap
|
||
|
*/
|
||
|
static br_error TextureHeapExpand(void)
|
||
|
{
|
||
|
heap_memory_block *newblock;
|
||
|
MSImemptr heap;
|
||
|
|
||
|
heap = msiAllocTextureHeap(HEAP_BLOCK_PAGES);
|
||
|
|
||
|
if (!heap)
|
||
|
return(BRE_DEV_NO_MEMORY);
|
||
|
|
||
|
newblock = BrResAllocate(DRIVER_RESOURCE, sizeof(heap_memory_block), BR_MEMORY_SCRATCH);
|
||
|
if (!newblock) {
|
||
|
msiFreeTextureHeap(heap);
|
||
|
return(BRE_DEV_FAIL); // Different error to indicate severe failure
|
||
|
}
|
||
|
|
||
|
/* Setup and link into list */
|
||
|
newblock->heap = heap;
|
||
|
newblock->mem = heap;
|
||
|
newblock->size = MAX_HEAP_OBJECT_SIZE;
|
||
|
newblock->next = heap_list;
|
||
|
heap_list = newblock;
|
||
|
|
||
|
return(BRE_OK);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Allocate heap memory
|
||
|
*/
|
||
|
static heap_memory_block *TextureHeapMalloc(br_uint_32 size)
|
||
|
{
|
||
|
heap_memory_block *last, *block, *newblock;
|
||
|
|
||
|
/* Align size to dword boundary to keep all allocations on dword boundaries */
|
||
|
size = (size + 3) & ~3;
|
||
|
|
||
|
/* Clip out anything too large to go in our heap */
|
||
|
if (size > MAX_HEAP_OBJECT_SIZE)
|
||
|
return(NULL);
|
||
|
|
||
|
/* Search free list for a valid block */
|
||
|
for(block=heap_list,last=NULL; block; last=block,block = block->next)
|
||
|
if (size <= block->size)
|
||
|
break;
|
||
|
|
||
|
if (!block) {
|
||
|
/* Expand heap if possible */
|
||
|
if (TextureHeapExpand() != BRE_OK)
|
||
|
return(NULL); /* Can't expand, so give up */
|
||
|
|
||
|
/* Can always fit into the first block on the list now */
|
||
|
block = heap_list;
|
||
|
last = NULL;
|
||
|
}
|
||
|
|
||
|
/* Can return entire block if it is exactly the right size, else need to split */
|
||
|
if (block->size != size) {
|
||
|
/* Split block to allocate */
|
||
|
newblock = BrResAllocate(DRIVER_RESOURCE, sizeof(heap_memory_block), BR_MEMORY_SCRATCH);
|
||
|
if (!newblock)
|
||
|
return(NULL);
|
||
|
newblock->heap = block->heap;
|
||
|
newblock->mem = block->mem + size;
|
||
|
newblock->size = block->size - size;
|
||
|
newblock->next = block->next;
|
||
|
block->size = size;
|
||
|
|
||
|
block->next = newblock;
|
||
|
}
|
||
|
|
||
|
/* Unlink */
|
||
|
if (last) last->next = block->next;
|
||
|
else heap_list = block->next;
|
||
|
block->next = NULL;
|
||
|
|
||
|
return(block);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Free heap memory
|
||
|
*/
|
||
|
static void TextureHeapFree(heap_memory_block *block)
|
||
|
{
|
||
|
heap_memory_block *lastlast, *last, *next;
|
||
|
MSImemptr heap;
|
||
|
|
||
|
/* All checks must be in same heap */
|
||
|
heap = block->heap;
|
||
|
|
||
|
/* Relink into free list: warning, nightmare code! */
|
||
|
for(next=heap_list,last=NULL,lastlast=NULL;
|
||
|
next;
|
||
|
lastlast=last,last=next,next = next->next) {
|
||
|
/* Search until at least one of the two blocks is in the right heap */
|
||
|
if ((last && (last->heap == heap)) || (next->heap == heap)) {
|
||
|
|
||
|
/* Block must fit in between last and next in same heap: this is
|
||
|
* legal in DOS version as only comparing between memory on same
|
||
|
* heap, and therefore the same selector */
|
||
|
if ((!last || (heap != last->heap) || (block->mem > last->mem)) &&
|
||
|
((heap != next->heap) ||(block->mem < next->mem)) )
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Check for empty block afterwards: again, legal because same heap i.e. same selector
|
||
|
* is always checked before doing any pointer arithmetic */
|
||
|
if (next) {
|
||
|
if ((heap == next->heap) &&
|
||
|
((block->mem + block->size) == next->mem)) {
|
||
|
/* Concatenate */
|
||
|
block->size += next->size;
|
||
|
block->next = next->next;
|
||
|
BrResFree(next);
|
||
|
} else {
|
||
|
/* Relink instead */
|
||
|
block->next = next;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Check for empty block before: again legal on same heap */
|
||
|
if (last) {
|
||
|
if ((heap == last->heap) && ((last->mem + last->size) == block->mem)) {
|
||
|
|
||
|
/* Concatenate */
|
||
|
last->size += block->size;
|
||
|
last->next = block->next;
|
||
|
BrResFree(block);
|
||
|
block = last; // Store for heap free check
|
||
|
last = lastlast; // Make last valid again
|
||
|
} else {
|
||
|
/* Relink instead */
|
||
|
last->next = block;
|
||
|
}
|
||
|
} else {
|
||
|
heap_list = block;
|
||
|
}
|
||
|
|
||
|
#ifdef USE_HEAP_FREEING
|
||
|
/* If this block is an entire texture heap, attempt to free it here, which
|
||
|
* is cleaner and neater and shuts up MSI's debug warnings. */
|
||
|
if (block->size == MAX_HEAP_OBJECT_SIZE) {
|
||
|
if (!msiFreeTextureHeap(block->heap))
|
||
|
return;
|
||
|
|
||
|
if (last)
|
||
|
last->next = block->next;
|
||
|
else
|
||
|
heap_list = block->next;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
#ifdef _WIN32
|
||
|
|
||
|
|
||
|
#ifdef USE_TEXTURE_HEAP
|
||
|
#define HEAP_LIST_SIZE 4096 // Max of 4096 textures... should be OK
|
||
|
static br_buffer_stored *on_heap_list[HEAP_LIST_SIZE];
|
||
|
#endif
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Move a pixelmap's pixel data to the heap
|
||
|
*/
|
||
|
br_error MovePixelmapToHeap(br_buffer_stored *buffer)
|
||
|
{
|
||
|
#ifdef USE_TEXTURE_HEAP
|
||
|
void *sysmemptr;
|
||
|
heap_memory_block *heapptr;
|
||
|
br_uint_32 size;
|
||
|
int i;
|
||
|
|
||
|
if (buffer->flags & SBUF_ON_HEAP)
|
||
|
return(BRE_DEV_FAIL);
|
||
|
|
||
|
sysmemptr = buffer->pixelmap->pixels;
|
||
|
size = buffer->buffer.size;
|
||
|
|
||
|
/* Allocate heap memory; if we can't, then the heap must be full */
|
||
|
heapptr = TextureHeapMalloc(size);
|
||
|
if (!heapptr)
|
||
|
return(BRE_DEV_NO_VIDEO_MEMORY);
|
||
|
|
||
|
/* Move it */
|
||
|
memcpy(heapptr->mem, sysmemptr, size);
|
||
|
|
||
|
/* Reprogram pixelmap structure */
|
||
|
buffer->pixelmap->pixels = heapptr->mem;
|
||
|
|
||
|
/* Clear out old pixel storage */
|
||
|
BrResFree(sysmemptr);
|
||
|
|
||
|
/* Mark it on the heap */
|
||
|
buffer->flags |= SBUF_ON_HEAP;
|
||
|
buffer->heap_block = heapptr;
|
||
|
buffer->buffer.heap = heapptr->heap;
|
||
|
buffer->buffer.base = heapptr->mem;
|
||
|
|
||
|
/* Add to the list of blocks on the heap */
|
||
|
for(i=0; i<HEAP_LIST_SIZE; i++) {
|
||
|
if (on_heap_list[i] == NULL) {
|
||
|
on_heap_list[i] = buffer;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
return(BRE_OK);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Return a heap pixelmap pixel data to normal memory
|
||
|
*/
|
||
|
br_error MovePixelmapFromHeap(br_buffer_stored *buffer)
|
||
|
{
|
||
|
#ifdef USE_TEXTURE_HEAP
|
||
|
void *sysmemptr;
|
||
|
heap_memory_block *heapptr;
|
||
|
br_uint_32 size;
|
||
|
int i;
|
||
|
|
||
|
if (!(buffer->flags & SBUF_ON_HEAP))
|
||
|
return(BRE_DEV_FAIL);
|
||
|
|
||
|
size = buffer->buffer.size;
|
||
|
heapptr = buffer->heap_block;
|
||
|
|
||
|
/* Reallocate system memory */
|
||
|
sysmemptr = BrResAllocate(buffer->pixelmap, size, BR_MEMORY_PIXELS);
|
||
|
if (!sysmemptr)
|
||
|
return(BRE_DEV_NO_MEMORY);
|
||
|
|
||
|
/* Move it */
|
||
|
memcpy(sysmemptr, heapptr->mem, size);
|
||
|
|
||
|
/* Reprogram pixelmap structure */
|
||
|
buffer->pixelmap->pixels = sysmemptr;
|
||
|
|
||
|
/* Clear out old pixel storage */
|
||
|
TextureHeapFree(heapptr);
|
||
|
|
||
|
/* Mark it on the heap */
|
||
|
buffer->flags &= ~SBUF_ON_HEAP;
|
||
|
buffer->heap_block = NULL;
|
||
|
|
||
|
buffer->buffer.base = sysmemptr;
|
||
|
|
||
|
buffer->buffer.heap = NULL;
|
||
|
|
||
|
/* Remove from the list of blocks on the heap */
|
||
|
for(i=0; i<HEAP_LIST_SIZE; i++) {
|
||
|
if (on_heap_list[i] == buffer) {
|
||
|
on_heap_list[i] = NULL;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
return(BRE_OK);
|
||
|
}
|
||
|
|
||
|
|
||
|
#ifdef USE_TEXTURE_HEAP
|
||
|
/*
|
||
|
* Clear all the stored buffers out of the texture heap
|
||
|
*
|
||
|
* I know... this should be done automatically... but the timing gets a bit messy
|
||
|
* on shutdown - the device pixelmap free doesn't free the stored buffers because
|
||
|
* the stored buffers are children of the primitive library which is a child of the
|
||
|
* device... <sigh> so instead it's hack time.
|
||
|
*/
|
||
|
void ClearHeap(void)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
for(i=0; i<HEAP_LIST_SIZE; i++)
|
||
|
if (on_heap_list[i])
|
||
|
MovePixelmapFromHeap(on_heap_list[i]);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
|
||
|
#else // _WIN32
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
* DOS method to copy a pixelmap to the heap
|
||
|
*/
|
||
|
br_error CopyPixelmapToHeap(br_buffer_stored *buffer)
|
||
|
{
|
||
|
void *sysmemptr;
|
||
|
br_uint_32 size;
|
||
|
|
||
|
sysmemptr = buffer->pixelmap->pixels;
|
||
|
size = buffer->buffer.size;
|
||
|
|
||
|
/* First time this one has been moved across: create memory */
|
||
|
if (!buffer->buffer.heap) {
|
||
|
heap_memory_block *heapptr;
|
||
|
|
||
|
/* Allocate heap memory; if we can't, then the heap must be full */
|
||
|
heapptr = TextureHeapMalloc(size);
|
||
|
if (!heapptr)
|
||
|
return(BRE_DEV_NO_VIDEO_MEMORY);
|
||
|
|
||
|
buffer->heap_block = heapptr;
|
||
|
buffer->buffer.heap = heapptr->heap;
|
||
|
buffer->buffer.base = heapptr->mem;
|
||
|
|
||
|
buffer->flags |= SBUF_ON_HEAP;
|
||
|
|
||
|
}
|
||
|
|
||
|
/* Copy it */
|
||
|
_fmemcpy(buffer->buffer.base, sysmemptr, size);
|
||
|
|
||
|
return(BRE_OK);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
#endif // _WIN32
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Check if a number of a power of 2
|
||
|
*/
|
||
|
static br_boolean isPowerOf2(br_int_32 x)
|
||
|
{
|
||
|
return !((x-1) & x);
|
||
|
}
|
||
|
|
||
|
static pixelmapBPP(br_device_pixelmap *pm)
|
||
|
{
|
||
|
switch(pm->pm_type) {
|
||
|
default:
|
||
|
return 1;
|
||
|
case BR_PMT_RGB_555:
|
||
|
case BR_PMT_RGB_565:
|
||
|
case BR_PMT_DEPTH_16:
|
||
|
return 2;
|
||
|
|
||
|
case BR_PMT_RGB_888:
|
||
|
return 3;
|
||
|
|
||
|
case BR_PMT_RGBX_888:
|
||
|
case BR_PMT_RGBA_8888:
|
||
|
return 4;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Set up the stored buffer, inside which is the renderbuffer used to
|
||
|
* render the texture.
|
||
|
*
|
||
|
* Under Windows, move the pixelmap to the heap if possible. Under DOS, copy the
|
||
|
* pixelmap to the heap - if it isn't possible, it won't be rendered.
|
||
|
*/
|
||
|
br_error SetupMystBuffer(br_buffer_stored *buffer, br_device_pixelmap *pm)
|
||
|
{
|
||
|
br_colour *map;
|
||
|
heap_memory_block *palette_heap_block;
|
||
|
br_uint_16 *op;
|
||
|
br_uint_32 i;
|
||
|
|
||
|
/* Free palette if already allocated internally */
|
||
|
if (buffer->palette_heap_block) {
|
||
|
TextureHeapFree(buffer->palette_heap_block);
|
||
|
buffer->palette_heap_block = NULL;
|
||
|
}
|
||
|
#ifdef _WIN32
|
||
|
else if (buffer->buffer.palette) {
|
||
|
BrResFree(buffer->buffer.palette);
|
||
|
buffer->buffer.palette = NULL;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/* Any failure inside here will make the texture uncacheable and unrenderable */
|
||
|
buffer->buffer.uncacheable = BR_TRUE;
|
||
|
|
||
|
//return(BRE_DEV_UNSUPPORTED);
|
||
|
|
||
|
/* Inspect the texture for legality */
|
||
|
if(pm->pm_width < 8 || pm->pm_height < 8)
|
||
|
return BRE_DEV_UNSUPPORTED;
|
||
|
if(pm->pm_width > 1024 || pm->pm_height > 1024)
|
||
|
return BRE_DEV_UNSUPPORTED;
|
||
|
if(!isPowerOf2(pm->pm_width) || !isPowerOf2(pm->pm_height))
|
||
|
return BRE_DEV_UNSUPPORTED;
|
||
|
if ((pm->pm_base_x != 0) || (pm->pm_base_y != 0))
|
||
|
return BRE_DEV_UNSUPPORTED;
|
||
|
|
||
|
/* Copy across dimensions */
|
||
|
buffer->buffer.width_p = pm->pm_width;
|
||
|
buffer->buffer.width_b = pm->pm_width * pixelmapBPP(pm);
|
||
|
buffer->buffer.height = pm->pm_height;
|
||
|
|
||
|
/* BRender and the Mystique disagree slightly in terms of the definition of
|
||
|
* texture coordinates (I think). My interpretation of the problem is that the
|
||
|
* BRender specification is that 1.0 corresponds to the centre of the _last_
|
||
|
* column or row of pixels on the texture, whereas the Mystique interpretations is
|
||
|
* that 1.0 is the wrap-around, i.e. 1.0 and 0.0 are equivalent. Personally I
|
||
|
* think that the Mystique method is right. Therefore we just need to calculate
|
||
|
* the U and V ranges here, taking into account a correction factor to prevent
|
||
|
* partial textures seaming... */
|
||
|
#if 0
|
||
|
/*
|
||
|
* No as usual Dave is mouthing off without checking with someone on the BRender team first.
|
||
|
* (0.0, 0.0) corresponds to the top-left of the top-left pixel, (1.0, 0.0) corresponds to the
|
||
|
* same place one tile to the right.
|
||
|
*
|
||
|
* Either the hardware rasterises badly or 0.0 is the CENTRE of the top-left pixel, in which case
|
||
|
* an offset of (-0.5,-0.5) is required. But I tried that and it changes the problem, it didn't
|
||
|
* eliminate it.
|
||
|
*/
|
||
|
buffer->buffer.u_range = BrFloatToScalar(1.0f - (1.0f/(pm->pm_width-1.0f)));
|
||
|
buffer->buffer.v_range = BrFloatToScalar(1.0f - (1.0f/(pm->pm_height-1.0f)));
|
||
|
#endif
|
||
|
|
||
|
/* Pixelmap must be unstrided */
|
||
|
if (pm->pm_row_bytes != buffer->buffer.width_b)
|
||
|
return BRE_DEV_UNSUPPORTED;
|
||
|
|
||
|
/* Set size, align to 32 bytes for maximum cache efficiency */
|
||
|
buffer->buffer.size = (buffer->buffer.width_b * buffer->buffer.height + 0x1f) & ~0x1f;
|
||
|
|
||
|
/*
|
||
|
* Set up the bits per pixel and any palette information:
|
||
|
*/
|
||
|
buffer->buffer.palette_heap = NULL;
|
||
|
buffer->buffer.palette = NULL;
|
||
|
|
||
|
switch(pm->pm_type) {
|
||
|
case BR_PMT_INDEX_8:
|
||
|
buffer->buffer.bits = 8;
|
||
|
|
||
|
/* Build palette: this is a 16-bit 256-entry palette */
|
||
|
if (pm->pm_map)
|
||
|
map = pm->pm_map->pixels;
|
||
|
else
|
||
|
map = ObjectDevice(buffer)->clut->entries;
|
||
|
|
||
|
if (!map)
|
||
|
return(BRE_DEV_UNSUPPORTED);
|
||
|
|
||
|
#ifdef USE_TEXTURE_HEAP
|
||
|
if (palette_heap_block = TextureHeapMalloc(512)) {
|
||
|
buffer->buffer.palette_heap = palette_heap_block->heap;
|
||
|
buffer->buffer.palette = palette_heap_block->mem;
|
||
|
buffer->palette_heap_block = palette_heap_block;
|
||
|
} else
|
||
|
#endif
|
||
|
|
||
|
#ifdef _WIN32
|
||
|
{ /* Else case if texture heap load failed */
|
||
|
buffer->buffer.palette = BrResAllocate(DRIVER_RESOURCE, 512, BR_MEMORY_DRIVER);
|
||
|
buffer->buffer.palette_heap = NULL;
|
||
|
buffer->palette_heap_block = NULL;
|
||
|
}
|
||
|
#else
|
||
|
return(BRE_DEV_UNSUPPORTED); // palettes must be on the heap in DOS version
|
||
|
#endif
|
||
|
|
||
|
if (!buffer->buffer.palette)
|
||
|
return(BRE_DEV_UNSUPPORTED);
|
||
|
|
||
|
op = (br_uint_16 *) buffer->buffer.palette;
|
||
|
for(i=0;i<256;i++) {
|
||
|
*op++ = ((BR_RED(map[i]) & 0xf8) << 8) +
|
||
|
((BR_GRN(map[i]) & 0xfc) << 3) +
|
||
|
((BR_BLU(map[i]) & 0xf8) >> 3);
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
case BR_PMT_RGB_555:
|
||
|
buffer->buffer.bits = 15;
|
||
|
break;
|
||
|
|
||
|
case BR_PMT_RGB_565:
|
||
|
buffer->buffer.bits = 16;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
return(BRE_DEV_UNSUPPORTED);
|
||
|
}
|
||
|
|
||
|
#ifdef _WIN32
|
||
|
/* Having got this far, it's definitely possible to move the pixelmap across to heap memory.
|
||
|
* as long as: 1. it's not already there and 2. the application hasn't requested
|
||
|
* it not to move */
|
||
|
if (!(buffer->flags & SBUF_ON_HEAP) && !(buffer->flags & SBUF_PREFER_SHARE))
|
||
|
MovePixelmapToHeap(buffer);
|
||
|
|
||
|
#else
|
||
|
/* Under DOS, copy it to the heap */
|
||
|
CopyPixelmapToHeap(buffer);
|
||
|
|
||
|
/* If it couldn't be copied to the heap, then it can't be rendered */
|
||
|
if (!buffer->buffer.heap)
|
||
|
return(BRE_DEV_NO_MEMORY);
|
||
|
#endif
|
||
|
|
||
|
|
||
|
/* It's all OK, so we can mark it as usable now! */
|
||
|
buffer->buffer.uncacheable = BR_FALSE;
|
||
|
|
||
|
return BRE_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Set up stored buffer object to represent a texture
|
||
|
*/
|
||
|
struct br_buffer_stored *BufferStoredSoftAllocateMyst(struct br_primitive_library *plib,
|
||
|
br_token use, struct br_device_pixelmap *pm, br_token_value *tv)
|
||
|
{
|
||
|
struct br_buffer_stored * self;
|
||
|
char *ident;
|
||
|
struct sbufferAllocate_tokens sba;
|
||
|
br_int_32 count;
|
||
|
|
||
|
switch(use) {
|
||
|
case BRT_TEXTURE_O:
|
||
|
case BRT_COLOUR_MAP_O:
|
||
|
ident = pm->pm_identifier;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
self = BrResAllocate(DRIVER_RESOURCE, sizeof(*self), BR_MEMORY_OBJECT);
|
||
|
if(self == NULL)
|
||
|
return NULL;
|
||
|
|
||
|
/* Parse for buffer flags */
|
||
|
sbufferAllocateTemplate.res = DRIVER_RESOURCE;
|
||
|
sba.flags = SBUF_SHARED;
|
||
|
BrTokenValueSetMany(&sba, &count, NULL, tv, &sbufferAllocateTemplate);
|
||
|
self->flags = sba.flags;
|
||
|
|
||
|
/* Set up defaults */
|
||
|
self->dispatch = &bufferStoredDispatch;
|
||
|
if (ident)
|
||
|
self->identifier = BrResStrDup(self, ident);
|
||
|
else
|
||
|
self->identifier = "Texture";
|
||
|
self->plib = plib;
|
||
|
self->pixelmap = (br_pixelmap *) pm;
|
||
|
self->buffer.on_card = BR_FALSE;
|
||
|
self->heap_block = NULL;
|
||
|
self->palette_heap_block = NULL;
|
||
|
|
||
|
/* Build the render-buffer */
|
||
|
SetupMystBuffer(self, pm);
|
||
|
|
||
|
ObjectContainerAddFront(plib, (br_object *)self);
|
||
|
|
||
|
return self;
|
||
|
}
|
||
|
|
||
|
|
||
|
static br_error BR_CMETHOD_DECL(br_buffer_stored_mystique, update)(
|
||
|
struct br_buffer_stored *self,
|
||
|
struct br_device_pixelmap *pm,
|
||
|
br_token_value *tv)
|
||
|
{
|
||
|
/* Clear the entry out of the texture cache if it is already in there */
|
||
|
TextureCacheClearEntry(&self->buffer);
|
||
|
|
||
|
if (self->pixelmap != (br_pixelmap *) pm) {
|
||
|
/* Hmmmm problems! */
|
||
|
return(BRE_DEV_FAIL);
|
||
|
}
|
||
|
|
||
|
/* Rebuild the texture buffer */
|
||
|
SetupMystBuffer(self, pm);
|
||
|
|
||
|
return BRE_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
static void BR_CMETHOD_DECL(br_buffer_stored_mystique, free)(br_buffer_stored *self)
|
||
|
{
|
||
|
/* Remove from card memory if uploaded */
|
||
|
TextureCacheClearEntry(&self->buffer);
|
||
|
|
||
|
#ifdef _WIN32
|
||
|
/* Return pixelmap to normal system memory */
|
||
|
if (self->flags & SBUF_ON_HEAP)
|
||
|
MovePixelmapFromHeap(self);
|
||
|
|
||
|
/* Free palette if allocated */
|
||
|
if (self->palette_heap_block)
|
||
|
TextureHeapFree(self->palette_heap_block);
|
||
|
else if (self->buffer.palette)
|
||
|
BrResFree(self->buffer.palette);
|
||
|
|
||
|
#else
|
||
|
/* DOS version has copy of pixelmap and palette on heap, so free them */
|
||
|
if (self->heap_block)
|
||
|
TextureHeapFree(self->heap_block);
|
||
|
|
||
|
if (self->palette_heap_block)
|
||
|
TextureHeapFree(self->palette_heap_block);
|
||
|
#endif
|
||
|
|
||
|
/* Free object */
|
||
|
ObjectContainerRemove(self->plib, (br_object *)self);
|
||
|
BrResFreeNoCallback(self);
|
||
|
}
|
||
|
|
||
|
static br_token BR_CMETHOD_DECL(br_buffer_stored_mystique, type)(br_buffer_stored *self)
|
||
|
{
|
||
|
return BRT_BUFFER_STORED;
|
||
|
}
|
||
|
|
||
|
static br_boolean BR_CMETHOD_DECL(br_buffer_stored_mystique, 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_mystique, space)(br_buffer_stored *self)
|
||
|
{
|
||
|
return BrResSizeTotal(self);
|
||
|
}
|
||
|
|
||
|
static struct br_tv_template * BR_CMETHOD_DECL(br_buffer_stored_mystique,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_mystique, free),
|
||
|
BR_CMETHOD_REF(br_object_mystique, identifier),
|
||
|
BR_CMETHOD_REF(br_buffer_stored_mystique, type),
|
||
|
BR_CMETHOD_REF(br_buffer_stored_mystique, isType),
|
||
|
BR_CMETHOD_REF(br_object_mystique, device),
|
||
|
BR_CMETHOD_REF(br_buffer_stored_mystique, space),
|
||
|
|
||
|
BR_CMETHOD_REF(br_buffer_stored_mystique, 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_mystique, update),
|
||
|
};
|
||
|
|