blob: d2b9a1ab31179ebcd26eb0d85af2dde7766cdbe7 [file] [log] [blame]
/**************************************************************************
*
* Copyright 2007 Tungsten Graphics, Inc., Bismarck, ND., USA
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
*
**************************************************************************/
/*
* Authors:
* Keith Whitwell
* Brian Paul
*/
#include "util/u_memory.h"
#include "util/u_math.h"
#include "pipe/p_error.h"
#include "pipe/p_context.h"
#include "xm_winsys.h"
#include "i965/brw_winsys.h"
#include "i965/brw_screen.h"
#include "i965/brw_reg.h"
#include "i965/brw_structs_dump.h"
#define MAX_VRAM (128*1024*1024)
extern int brw_disasm (FILE *file,
const struct brw_instruction *inst,
unsigned count );
extern int intel_decode(const uint32_t *data,
int count,
uint32_t hw_offset,
uint32_t devid);
struct xlib_brw_buffer
{
struct brw_winsys_buffer base;
char *virtual;
unsigned offset;
unsigned type;
int map_count;
boolean modified;
};
/**
* Subclass of brw_winsys_screen for Xlib winsys
*/
struct xlib_brw_winsys
{
struct brw_winsys_screen base;
struct brw_chipset chipset;
unsigned size;
unsigned used;
};
static struct xlib_brw_winsys *
xlib_brw_winsys( struct brw_winsys_screen *screen )
{
return (struct xlib_brw_winsys *)screen;
}
static struct xlib_brw_buffer *
xlib_brw_buffer( struct brw_winsys_buffer *buffer )
{
return (struct xlib_brw_buffer *)buffer;
}
const char *names[BRW_BUFFER_TYPE_MAX] = {
"TEXTURE",
"SCANOUT",
"VERTEX",
"CURBE",
"QUERY",
"SHADER_CONSTANTS",
"WM_SCRATCH",
"BATCH",
"GENERAL_STATE",
"SURFACE_STATE",
"PIXEL",
"GENERIC",
};
const char *usages[BRW_USAGE_MAX] = {
"STATE",
"QUERY_RESULT",
"RENDER_TARGET",
"DEPTH_BUFFER",
"BLIT_SOURCE",
"BLIT_DEST",
"SAMPLER",
"VERTEX",
"SCRATCH"
};
const char *data_types[BRW_DATA_MAX] =
{
"GS: CC_VP",
"GS: CC_UNIT",
"GS: WM_PROG",
"GS: SAMPLER_DEFAULT_COLOR",
"GS: SAMPLER",
"GS: WM_UNIT",
"GS: SF_PROG",
"GS: SF_VP",
"GS: SF_UNIT",
"GS: VS_UNIT",
"GS: VS_PROG",
"GS: GS_UNIT",
"GS: GS_PROG",
"GS: CLIP_VP",
"GS: CLIP_UNIT",
"GS: CLIP_PROG",
"SS: SURFACE",
"SS: SURF_BIND",
"CONSTANT DATA",
"BATCH DATA",
"(untyped)"
};
static enum pipe_error
xlib_brw_bo_alloc( struct brw_winsys_screen *sws,
enum brw_buffer_type type,
unsigned size,
unsigned alignment,
struct brw_winsys_buffer **bo_out )
{
struct xlib_brw_winsys *xbw = xlib_brw_winsys(sws);
struct xlib_brw_buffer *buf;
if (BRW_DEBUG & DEBUG_WINSYS)
debug_printf("%s type %s sz %d align %d\n",
__FUNCTION__, names[type], size, alignment );
buf = CALLOC_STRUCT(xlib_brw_buffer);
if (!buf)
return PIPE_ERROR_OUT_OF_MEMORY;
pipe_reference_init(&buf->base.reference, 1);
buf->offset = align(xbw->used, alignment);
buf->type = type;
buf->virtual = MALLOC(size);
buf->base.size = size;
buf->base.sws = sws;
xbw->used = align(xbw->used, alignment) + size;
if (xbw->used > MAX_VRAM)
goto err;
/* XXX: possibly rentrant call to bo_destroy:
*/
bo_reference(bo_out, &buf->base);
return PIPE_OK;
err:
assert(0);
FREE(buf->virtual);
FREE(buf);
return PIPE_ERROR_OUT_OF_MEMORY;
}
static void
xlib_brw_bo_destroy( struct brw_winsys_buffer *buffer )
{
struct xlib_brw_buffer *buf = xlib_brw_buffer(buffer);
FREE(buf);
}
static int
xlib_brw_bo_emit_reloc( struct brw_winsys_buffer *buffer,
enum brw_buffer_usage usage,
unsigned delta,
unsigned offset,
struct brw_winsys_buffer *buffer2)
{
struct xlib_brw_buffer *buf = xlib_brw_buffer(buffer);
struct xlib_brw_buffer *buf2 = xlib_brw_buffer(buffer2);
if (BRW_DEBUG & DEBUG_WINSYS)
debug_printf("%s buf %p offset %x val %x + %x buf2 %p/%s/%s\n",
__FUNCTION__, (void *)buffer, offset,
buf2->offset, delta,
(void *)buffer2, names[buf2->type], usages[usage]);
*(uint32_t *)(buf->virtual + offset) = buf2->offset + delta;
return 0;
}
static int
xlib_brw_bo_exec( struct brw_winsys_buffer *buffer,
unsigned bytes_used )
{
if (BRW_DEBUG & DEBUG_WINSYS)
debug_printf("execute buffer %p, bytes %d\n", (void *)buffer, bytes_used);
return 0;
}
static int
xlib_brw_bo_subdata(struct brw_winsys_buffer *buffer,
enum brw_buffer_data_type data_type,
size_t offset,
size_t size,
const void *data,
const struct brw_winsys_reloc *reloc,
unsigned nr_relocs)
{
struct xlib_brw_buffer *buf = xlib_brw_buffer(buffer);
struct xlib_brw_winsys *xbw = xlib_brw_winsys(buffer->sws);
unsigned i;
if (BRW_DEBUG & DEBUG_WINSYS)
debug_printf("%s buf %p off %d sz %d %s relocs: %d\n",
__FUNCTION__,
(void *)buffer, offset, size,
data_types[data_type],
nr_relocs);
assert(buf->base.size >= offset + size);
memcpy(buf->virtual + offset, data, size);
/* Apply the relocations:
*/
for (i = 0; i < nr_relocs; i++) {
if (BRW_DEBUG & DEBUG_WINSYS)
debug_printf("\treloc[%d] usage %s off %d value %x+%x\n",
i, usages[reloc[i].usage], reloc[i].offset,
xlib_brw_buffer(reloc[i].bo)->offset, reloc[i].delta);
*(unsigned *)(buf->virtual + offset + reloc[i].offset) =
xlib_brw_buffer(reloc[i].bo)->offset + reloc[i].delta;
}
if (BRW_DUMP)
brw_dump_data( xbw->chipset.pci_id,
data_type,
buf->offset + offset,
buf->virtual + offset, size );
return 0;
}
static boolean
xlib_brw_bo_is_busy(struct brw_winsys_buffer *buffer)
{
if (BRW_DEBUG & DEBUG_WINSYS)
debug_printf("%s %p\n", __FUNCTION__, (void *)buffer);
return TRUE;
}
static boolean
xlib_brw_bo_references(struct brw_winsys_buffer *a,
struct brw_winsys_buffer *b)
{
if (BRW_DEBUG & DEBUG_WINSYS)
debug_printf("%s %p %p\n", __FUNCTION__, (void *)a, (void *)b);
return TRUE;
}
static enum pipe_error
xlib_brw_check_aperture_space( struct brw_winsys_screen *iws,
struct brw_winsys_buffer **buffers,
unsigned count )
{
unsigned tot_size = 0;
unsigned i;
for (i = 0; i < count; i++)
tot_size += buffers[i]->size;
if (BRW_DEBUG & DEBUG_WINSYS)
debug_printf("%s %d bufs, tot_size: %d kb\n",
__FUNCTION__, count,
(tot_size + 1023) / 1024);
return PIPE_OK;
}
static void *
xlib_brw_bo_map(struct brw_winsys_buffer *buffer,
enum brw_buffer_data_type data_type,
unsigned offset,
unsigned length,
boolean write,
boolean discard,
boolean explicit)
{
struct xlib_brw_buffer *buf = xlib_brw_buffer(buffer);
if (BRW_DEBUG & DEBUG_WINSYS)
debug_printf("%s %p %s %s\n", __FUNCTION__, (void *)buffer,
write ? "read/write" : "read",
write ? data_types[data_type] : "");
if (write)
buf->modified = 1;
buf->map_count++;
return buf->virtual;
}
static void
xlib_brw_bo_flush_range( struct brw_winsys_buffer *buffer,
unsigned offset,
unsigned length )
{
}
static void
xlib_brw_bo_unmap(struct brw_winsys_buffer *buffer)
{
struct xlib_brw_buffer *buf = xlib_brw_buffer(buffer);
if (BRW_DEBUG & DEBUG_WINSYS)
debug_printf("%s %p\n", __FUNCTION__, (void *)buffer);
--buf->map_count;
assert(buf->map_count >= 0);
if (buf->map_count == 0 &&
buf->modified) {
buf->modified = 0;
/* Consider dumping new buffer contents here, using the
* flush-range info to minimize verbosity.
*/
}
}
static void
xlib_brw_bo_wait_idle( struct brw_winsys_buffer *buffer )
{
}
static void
xlib_brw_winsys_destroy( struct brw_winsys_screen *sws )
{
struct xlib_brw_winsys *xbw = xlib_brw_winsys(sws);
FREE(xbw);
}
static struct brw_winsys_screen *
xlib_create_brw_winsys_screen( void )
{
struct xlib_brw_winsys *ws;
ws = CALLOC_STRUCT(xlib_brw_winsys);
if (!ws)
return NULL;
ws->used = 0;
ws->base.destroy = xlib_brw_winsys_destroy;
ws->base.bo_alloc = xlib_brw_bo_alloc;
ws->base.bo_destroy = xlib_brw_bo_destroy;
ws->base.bo_emit_reloc = xlib_brw_bo_emit_reloc;
ws->base.bo_exec = xlib_brw_bo_exec;
ws->base.bo_subdata = xlib_brw_bo_subdata;
ws->base.bo_is_busy = xlib_brw_bo_is_busy;
ws->base.bo_references = xlib_brw_bo_references;
ws->base.check_aperture_space = xlib_brw_check_aperture_space;
ws->base.bo_map = xlib_brw_bo_map;
ws->base.bo_flush_range = xlib_brw_bo_flush_range;
ws->base.bo_unmap = xlib_brw_bo_unmap;
ws->base.bo_wait_idle = xlib_brw_bo_wait_idle;
return &ws->base;
}
/***********************************************************************
* Implementation of Xlib co-state-tracker's winsys interface
*/
static void
xlib_i965_display_surface(struct xmesa_buffer *xm_buffer,
struct pipe_surface *surf)
{
struct brw_surface *surface = brw_surface(surf);
struct xlib_brw_buffer *bo = xlib_brw_buffer(surface->bo);
if (BRW_DEBUG & DEBUG_WINSYS)
debug_printf("%s offset %x+%x sz %dx%d\n", __FUNCTION__,
bo->offset,
surface->draw_offset,
surf->width,
surf->height);
}
static void
xlib_i965_flush_frontbuffer(struct pipe_screen *screen,
struct pipe_surface *surf,
void *context_private)
{
xlib_i965_display_surface(NULL, surf);
}
static struct pipe_screen *
xlib_create_i965_screen( void )
{
struct brw_winsys_screen *winsys;
struct pipe_screen *screen;
winsys = xlib_create_brw_winsys_screen();
if (winsys == NULL)
return NULL;
screen = brw_create_screen(winsys, PCI_CHIP_GM45_GM);
if (screen == NULL)
goto fail;
xlib_brw_winsys(winsys)->chipset = brw_screen(screen)->chipset;
screen->flush_frontbuffer = xlib_i965_flush_frontbuffer;
return screen;
fail:
if (winsys)
winsys->destroy( winsys );
return NULL;
}
static struct pipe_context *
xlib_create_i965_context( struct pipe_screen *screen,
void *context_private )
{
struct pipe_context *pipe;
pipe = brw_create_context(screen);
if (pipe == NULL)
goto fail;
pipe->priv = context_private;
return pipe;
fail:
/* Free stuff here */
return NULL;
}
struct xm_driver xlib_i965_driver =
{
.create_pipe_screen = xlib_create_i965_screen,
.create_pipe_context = xlib_create_i965_context,
.display_surface = xlib_i965_display_surface
};
/* Register this driver at library load:
*/
static void _init( void ) __attribute__((constructor));
static void _init( void )
{
xmesa_set_driver( &xlib_i965_driver );
}
/***********************************************************************
*
* Butt-ugly hack to convince the linker not to throw away public GL
* symbols (they are all referenced from getprocaddress, I guess).
*/
extern void (*linker_foo(const unsigned char *procName))();
extern void (*glXGetProcAddress(const unsigned char *procName))();
extern void (*linker_foo(const unsigned char *procName))()
{
return glXGetProcAddress(procName);
}