brender-1997/d3drend/Sbuffer.c
2022-05-03 14:31:40 -07:00

499 lines
12 KiB
C

/*
* Copyright (c) 1993-1995 Argonaut Technologies Limited. All rights reserved.
*
* $Id: Sbuffer.c 1.3 1997/08/12 17:27:48 jon Exp JON $
* $Locker: JON $
*
* Stored buffer methods
*/
#include <stddef.h>
#include <string.h>
#include "drv.h"
#include "host.h"
#include "shortcut.h"
#include "brassert.h"
BR_RCS_ID("$Id: Sbuffer.c 1.3 1997/08/12 17:27:48 jon Exp JON $");
/*
* 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
/*
* Set up a static device object
*/
struct br_buffer_stored *BufferStoredD3DAllocate(br_renderer *renderer,
br_token use, struct br_device_pixelmap *pm, br_token_value *tv)
{
struct br_buffer_stored *self;
char *ident;
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;
case BRT_UNKNOWN:
ident ="Unknown";
break;
default:
return NULL;
}
self = BrResAllocate(renderer, sizeof(*self), BR_MEMORY_OBJECT);
if (self == NULL)
return NULL;
self->device = renderer->device;
self->dispatch = &bufferStoredDispatch;
self->identifier = ident;
self->renderer = renderer;
/*
* Should get this flag from the token-value arguments
*/
self->flags |= SBUFF_SHARED;
BufferStoredUpdate(self, pm, tv);
ObjectContainerAddFront(renderer, (br_object *)self);
return self;
}
static br_error BR_CMETHOD_DECL(br_buffer_stored_d3d, update)(
struct br_buffer_stored *self,
struct br_device_pixelmap *pm,
br_token_value *tv)
{
LPD3DDEVICEDESC tri_desc;
DDSURFACEDESC desc = { sizeof(DDSURFACEDESC) };
LPDDPIXELFORMAT stored_format;
br_uint_16 stored_width, stored_height;
br_boolean convert, stretch, alloconload;
LPDIRECTDRAWSURFACE surface;
LPDIRECTDRAWSURFACE2 dest_surface;
br_device *pm_device;
br_uint_16 ds;
DDBLTFX bltfx = { sizeof(DDBLTFX) };
HRESULT dderr;
br_uint_32 i;
/*
* Release any old interfaces
*/
self->handle = 0;
if (self->stored_texture != NULL) {
IDirect3DTexture2_Release(self->stored_texture);
self->stored_texture = NULL;
}
if (self->stored_surface != NULL) {
IDirectDrawSurface2_Release(self->stored_surface);
self->stored_surface = NULL;
}
if (self->source_texture != NULL) {
IDirect3DTexture2_Release(self->source_texture);
self->stored_texture = NULL;
}
if (self->source_surface != NULL) {
IDirectDrawSurface2_Release(self->source_surface);
self->source_surface = NULL;
}
self->source = (br_pixelmap *)pm;
/*
* Find out where the pixelmap comes from
*/
pm_device = ObjectDevice(pm);
if (pm_device == NULL) {
/*
* The pixelmap is a plain BRender memory pixelmap. Make sure that the pixels can be accessed
*/
if (pm->pm_flags & BR_PMF_NO_ACCESS || pm->pm_pixels == NULL)
return BRE_FAIL;
/*
* Make sure that the pixelmap has a near pointer
* N.B. Could try to map area in
*/
if (!(pm->pm_flags & BR_PMF_PIXELS_NEAR)) {
HostSelectorDS(&ds);
if (pm->pm_pixels_qualifier != ds)
return BRE_FAIL;
}
/*
* If the format or size of this pixelmap is not directly supported, find an alternative
*/
#if 1
convert = BR_FALSE;
if (PixelTypeToDDPixelFormat(&stored_format, pm->pm_type) != BRE_OK)
return BRE_FAIL;
#else
if (!self->renderer->texture_pixel_type[pm->pm_type].supported)
return BRE_FAIL;
convert = self->renderer->texture_pixel_type[pm->pm_type].convert;
stored_format = self->renderer->texture_pixel_type[pm->pm_type].pixel_format;
#endif
stored_width = pm->pm_width;
stored_height = pm->pm_height;
stretch = BR_FALSE;
//...
/*
* Work out whether we will be using the hal or the hel
*/
if (self->renderer->renderer_facility->d3d.hal_desc->dwFlags & D3DDD_TRICAPS)
tri_desc = self->renderer->renderer_facility->d3d.hal_desc;
else
tri_desc = self->renderer->renderer_facility->d3d.hel_desc;
/*
* Create the texture surface
*/
desc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
desc.dwHeight = stored_height;
desc.dwWidth = stored_width;
desc.ddpfPixelFormat = *stored_format;
surface = NULL;
alloconload = BR_FALSE;
/*
* N.B. Current strategy is always to try local video memory first because it is currently
* faster on everything
*/
/*
* Try to create an ALLOCONLOAD surface in local video memory
*
* *** Ought to implement a texture cache in case VRAM can't hold all of the textures ***
*/
#if 1
if (surface == NULL) {
#else
if (surface == NULL && tri_desc->dwDevCaps & D3DDEVCAPS_TEXTUREVIDEOMEMORY) {
#endif
desc.ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM | DDSCAPS_TEXTURE | DDSCAPS_ALLOCONLOAD;
if (IDirectDraw2_CreateSurface(self->renderer->renderer_facility->d3d.ddraw, &desc, &surface, NULL) == DD_OK)
alloconload = BR_TRUE;
}
/*
* Try to allocate a non-local video memory surface
*/
#if 1
if (surface == NULL) {
#else
if (surface == NULL && tri_desc->dwDevCaps & D3DDEVCAPS_TEXTURENONLOCALVIDMEM) {
#endif
desc.ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY | DDSCAPS_NONLOCALVIDMEM | DDSCAPS_TEXTURE;
IDirectDraw2_CreateSurface(self->renderer->renderer_facility->d3d.ddraw, &desc, &surface, NULL);
}
/*
* Try system memory
*/
#if 1
if (surface == NULL) {
#else
if (surface == NULL && tri_desc->dwDevCaps & D3DDEVCAPS_TEXTURESYSTEMMEMORY) {
#endif
desc.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_TEXTURE;
IDirectDraw2_CreateSurface(self->renderer->renderer_facility->d3d.ddraw, &desc, &surface, NULL);
}
if (surface == NULL)
return BRE_FAIL;
/*
* Get the new version of the surface interface and the texture interface
*/
if (IDirectDrawSurface_QueryInterface(surface, &IID_IDirectDrawSurface2, &self->stored_surface) != DD_OK) {
IDirectDrawSurface_Release(surface);
return BRE_FAIL;
}
IDirectDrawSurface_Release(surface);
if (IDirectDrawSurface2_QueryInterface(self->stored_surface, &IID_IDirect3DTexture2, &self->stored_texture) != DD_OK)
return BRE_FAIL;
/*
* Create an intermediate surface for ALLOCONLOAD textures, or where the stored surface
* is compressed
*/
if (alloconload || (stored_format->dwFlags & DDPF_COMPRESSED) != 0) {
desc.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_TEXTURE;
desc.ddpfPixelFormat.dwFlags &= ~DDPF_COMPRESSED;
if (IDirectDraw2_CreateSurface(self->renderer->renderer_facility->d3d.ddraw, &desc, &surface, NULL) != DD_OK)
return BRE_FAIL;
/*
* Get the new version of the surface interface and the texture interface
*/
if (IDirectDrawSurface_QueryInterface(surface, &IID_IDirectDrawSurface2, &self->source_surface) != DD_OK) {
IDirectDrawSurface_Release(surface);
return BRE_FAIL;
}
IDirectDrawSurface_Release(surface);
if (IDirectDrawSurface2_QueryInterface(self->source_surface, &IID_IDirect3DTexture2, &self->source_texture) != DD_OK)
return BRE_FAIL;
dest_surface = self->source_surface;
} else
/*
* Otherwise copy/convert directly to the texture
*/
dest_surface = self->stored_surface;
/*
* Copy or convert the data as necessary
*/
if (convert || stretch) {
/*
* If format or size conversion is necessary, use DirectDraw blit, Win32 blit or custom code
* to do it
*/
// Copy from source_surface into stored_surface, performing format and size conversion
//...
} else {
IDirectDrawSurface2_Lock(dest_surface, NULL, &desc, DDLOCK_NOSYSLOCK | DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL);
for (i = 0; i < pm->pm_height; i++)
memcpy((char *)desc.lpSurface + i * desc.lPitch, (char *)pm->pm_pixels + i * pm->pm_row_bytes, pm->pm_width * PixelTypePixelBytes(pm->pm_type));
IDirectDrawSurface2_Unlock(dest_surface, NULL);
}
/*
* If the intermediate pixelmap was only created for a non-ALLOCONLOAD compressed texture,
* copy it across and free it
*/
if (!alloconload && stored_format->dwFlags & DDPF_COMPRESSED) {
/*
* Just copy straight across
*/
do {
dderr = IDirectDrawSurface2_Blt(self->stored_surface, NULL, self->source_surface, NULL, DDBLT_WAIT, &bltfx);
switch (dderr) {
case DD_OK:
break;
case DDERR_SURFACELOST:
/*
* Not clear which surface is lost, so restore both.
*/
if (IDirectDrawSurface2_Restore(self->stored_surface) != DD_OK ||
IDirectDrawSurface2_Restore(self->source_surface) != DD_OK)
return BRE_FAIL;
break;
default:
return BRE_FAIL;
}
} while (dderr != DD_OK);
IDirectDrawSurface2_Release(self->source_surface);
self->source_surface = NULL;
}
/*
* *** SHOULD DEAL WITH ANY PALETTES! ***
*/
/*
* Set the alloc on load flag
*/
if (alloconload)
self->flags |= SBUFF_ALLOCONLOAD;
else
self->flags &= ~SBUFF_ALLOCONLOAD;
} else if (pm_device != self->device) {
/*
* The pixelmaps came from this device. We assume it to be valid texture already. Use it
* directly and get the texture interface
*/
self->stored_surface = pm->surface;
IDirectDrawSurface2_AddRef(pm->surface);
if (IDirectDrawSurface2_QueryInterface(self->stored_surface, &IID_IDirect3DTexture2, &self->stored_texture) != DD_OK)
return BRE_FAIL;
} else
/*
* The pixelmap is from another device, we can't use it
*/
return BRE_FAIL;
return BRE_OK;
}
static void BR_CMETHOD_DECL(br_buffer_stored_d3d, free)(br_buffer_stored *self)
{
/*
* Release any interfaces
*/
if (self->stored_texture != NULL) {
IDirect3DTexture2_Release(self->stored_texture);
self->stored_texture = NULL;
}
if (self->stored_surface != NULL) {
IDirectDrawSurface2_Release(self->stored_surface);
self->stored_surface = NULL;
}
if (self->source_texture != NULL) {
IDirect3DTexture2_Release(self->source_texture);
self->source_texture = NULL;
}
if (self->source_surface != NULL) {
IDirectDrawSurface2_Release(self->source_surface);
self->source_surface = NULL;
}
ObjectContainerRemove(self->renderer, (br_object *)self);
}
static char *BR_CMETHOD_DECL(br_buffer_stored_d3d, identifier)(br_buffer_stored *self)
{
return self->identifier;
}
static br_token BR_CMETHOD_DECL(br_buffer_stored_d3d, type)(br_buffer_stored *self)
{
return BRT_BUFFER_STORED;
}
static br_boolean BR_CMETHOD_DECL(br_buffer_stored_d3d, isType)(br_buffer_stored *self, br_token t)
{
return (t == BRT_BUFFER_STORED) || (t == BRT_OBJECT);
}
static br_device *BR_CMETHOD_DECL(br_buffer_stored_d3d, device)(br_buffer_stored *self)
{
return self->device;
}
static br_int_32 BR_CMETHOD_DECL(br_buffer_stored_d3d, space)(br_buffer_stored *self)
{
return BrResSizeTotal(self);
}
static struct br_tv_template * BR_CMETHOD_DECL(br_buffer_stored_d3d,templateQuery)
(br_buffer_stored *self)
{
if(self->device->templates.bufferStoredTemplate == NULL)
self->device->templates.bufferStoredTemplate = BrTVTemplateAllocate(self->device,
bufferStoredTemplateEntries,
BR_ASIZE(bufferStoredTemplateEntries));
return self->device->templates.bufferStoredTemplate ;
}
/*
* Default dispatch table for device
*/
static struct br_buffer_stored_dispatch bufferStoredDispatch = {
NULL,
NULL,
NULL,
NULL,
BR_CMETHOD_REF(br_buffer_stored_d3d, free),
BR_CMETHOD_REF(br_buffer_stored_d3d, identifier),
BR_CMETHOD_REF(br_buffer_stored_d3d, type),
BR_CMETHOD_REF(br_buffer_stored_d3d, isType),
BR_CMETHOD_REF(br_buffer_stored_d3d, device),
BR_CMETHOD_REF(br_buffer_stored_d3d, space),
BR_CMETHOD_REF(br_buffer_stored_d3d, 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_d3d, update),
};