nouveau: Very rough cut at gallium winsys + nv40 pipe driver.

This commit is contained in:
Ben Skeggs
2007-11-18 17:08:06 +11:00
parent 193c85ec7a
commit 2f33b5b56e
51 changed files with 12905 additions and 1 deletions
@@ -0,0 +1,38 @@
TOP = ../../../../..
include $(TOP)/configs/current
LIBNAME = nouveau_dri.so
MINIGLX_SOURCES =
PIPE_DRIVERS = \
$(TOP)/src/mesa/pipe/softpipe/libsoftpipe.a \
$(TOP)/src/mesa/pipe/nv40/libnv40.a
DRIVER_SOURCES = \
nouveau_bo.c \
nouveau_channel.c \
nouveau_context.c \
nouveau_device.c \
nouveau_dma.c \
nouveau_grobj.c \
nouveau_lock.c \
nouveau_notifier.c \
nouveau_screen.c \
nouveau_swapbuffers.c \
nouveau_winsys.c \
nouveau_winsys_pipe.c \
nouveau_winsys_softpipe.c \
nv04_region.c \
nv50_region.c
C_SOURCES = \
$(COMMON_SOURCES) \
$(DRIVER_SOURCES)
ASM_SOURCES =
include ../Makefile.template
symlinks:
@@ -0,0 +1,347 @@
/*
* Copyright 2007 Nouveau Project
*
* 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, sublicense,
* 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 above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* 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 NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS 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.
*/
#include <stdint.h>
#include <stdlib.h>
#include <errno.h>
#include "nouveau_drmif.h"
#include "nouveau_dma.h"
#include "nouveau_local.h"
int
nouveau_bo_init(struct nouveau_device *userdev)
{
struct nouveau_device_priv *nv = nouveau_device(userdev);
struct nouveau_channel *chan;
int ret;
if ((ret = nouveau_channel_alloc(userdev, 0x80000001, 0x80000002,
&nv->bufmgr.channel)))
return ret;
chan = nv->bufmgr.channel;
if ((ret = nouveau_notifier_alloc(nv->bufmgr.channel, 0x80000003, 1,
&nv->bufmgr.notify)))
return ret;
if ((ret = nouveau_grobj_alloc(nv->bufmgr.channel, 0x80000004, 0x39,
&nv->bufmgr.m2mf)))
return ret;
nouveau_notifier_reset(nv->bufmgr.notify, 0);
BEGIN_RING_CH(chan, nv->bufmgr.m2mf, 0x180, 1);
OUT_RING_CH (chan, nv->bufmgr.notify->handle);
BEGIN_RING_CH(chan, nv->bufmgr.m2mf, 0x104, 1);
OUT_RING_CH (chan, 0);
BEGIN_RING_CH(chan, nv->bufmgr.m2mf, 0x100, 1);
OUT_RING_CH (chan, 0);
FIRE_RING_CH (chan);
if ((ret = nouveau_notifier_wait_status(nv->bufmgr.notify, 0, 0, 2000)))
return ret;
return 0;
}
void
nouveau_bo_takedown(struct nouveau_device *userdev)
{
struct nouveau_device_priv *nv = nouveau_device(userdev);
nouveau_notifier_free(&nv->bufmgr.notify);
nouveau_grobj_free(&nv->bufmgr.m2mf);
nouveau_channel_free(&nv->bufmgr.channel);
}
static int
nouveau_bo_realloc_gpu(struct nouveau_bo_priv *bo, uint32_t flags, int size)
{
struct nouveau_device_priv *nv = nouveau_device(bo->base.device);
int ret;
if (bo->drm.size && bo->drm.size != size) {
struct drm_nouveau_mem_free f;
if (bo->map) {
drmUnmap(bo->map, bo->drm.size);
bo->map = NULL;
}
f.flags = bo->drm.flags;
f.offset = bo->drm.offset;
drmCommandWrite(nv->fd, DRM_NOUVEAU_MEM_FREE, &f, sizeof(f));
bo->drm.size = 0;
}
if (size && !bo->drm.size) {
if (flags) {
bo->drm.flags = 0;
if (flags & NOUVEAU_BO_VRAM)
bo->drm.flags |= NOUVEAU_MEM_FB;
if (flags & NOUVEAU_BO_GART)
bo->drm.flags |= (NOUVEAU_MEM_AGP |
NOUVEAU_MEM_PCI);
bo->drm.flags |= NOUVEAU_MEM_MAPPED;
}
bo->drm.size = size;
ret = drmCommandWriteRead(nv->fd, DRM_NOUVEAU_MEM_ALLOC,
&bo->drm, sizeof(bo->drm));
if (ret) {
free(bo);
return ret;
}
ret = drmMap(nv->fd, bo->drm.map_handle, bo->drm.size,
&bo->map);
if (ret) {
bo->map = NULL;
nouveau_bo_del((void *)&bo);
return ret;
}
}
return 0;
}
int
nouveau_bo_new(struct nouveau_device *userdev, uint32_t flags, int align,
int size, struct nouveau_bo **userbo)
{
struct nouveau_bo_priv *bo;
int ret;
if (!userdev || !userbo || *userbo)
return -EINVAL;
bo = calloc(1, sizeof(*bo));
if (!bo)
return -ENOMEM;
bo->base.device = userdev;
bo->drm.alignment = align;
if (flags & NOUVEAU_BO_PIN) {
ret = nouveau_bo_realloc_gpu(bo, flags, size);
if (ret) {
free(bo);
return ret;
}
} else {
bo->sysmem = malloc(size);
if (!bo->sysmem) {
free(bo);
return -ENOMEM;
}
}
bo->base.size = size;
bo->base.offset = bo->drm.offset;
bo->base.handle = (unsigned long)bo;
bo->refcount = 1;
*userbo = &bo->base;
return 0;
}
int
nouveau_bo_user(struct nouveau_device *userdev, void *ptr, int size,
struct nouveau_bo **userbo)
{
struct nouveau_bo_priv *bo;
if (!userdev || !userbo || *userbo)
return -EINVAL;
bo = calloc(1, sizeof(*bo));
if (!bo)
return -ENOMEM;
bo->base.device = userdev;
bo->sysmem = ptr;
bo->user = 1;
bo->base.size = size;
bo->base.offset = bo->drm.offset;
bo->base.handle = (unsigned long)bo;
bo->refcount = 1;
*userbo = &bo->base;
return 0;
}
int
nouveau_bo_ref(struct nouveau_device *userdev, uint64_t handle,
struct nouveau_bo **userbo)
{
struct nouveau_bo_priv *bo = (void *)(unsigned long)handle;
if (!userdev || !userbo || *userbo)
return -EINVAL;
bo->refcount++;
*userbo = &bo->base;
return 0;
}
int
nouveau_bo_resize(struct nouveau_bo *userbo, int size)
{
struct nouveau_bo_priv *bo = nouveau_bo(userbo);
int ret;
if (!bo || bo->user)
return -EINVAL;
if (bo->sysmem) {
bo->sysmem = realloc(bo->sysmem, size);
if (!bo->sysmem)
return -ENOMEM;
} else {
ret = nouveau_bo_realloc_gpu(bo, 0, size);
if (ret)
return ret;
}
bo->base.size = size;
return 0;
}
void
nouveau_bo_del(struct nouveau_bo **userbo)
{
struct nouveau_bo_priv *bo;
if (!userbo || !*userbo)
return;
bo = nouveau_bo(*userbo);
*userbo = NULL;
if (--bo->refcount)
return;
nouveau_bo_realloc_gpu(bo, 0, 0);
if (bo->sysmem && !bo->user)
free(bo->sysmem);
free(bo);
}
int
nouveau_bo_map(struct nouveau_bo *userbo, uint32_t flags)
{
struct nouveau_bo_priv *bo = nouveau_bo(userbo);
if (!bo)
return -EINVAL;
if (bo->sysmem)
userbo->map = bo->sysmem;
else
userbo->map = bo->map;
return 0;
}
void
nouveau_bo_unmap(struct nouveau_bo *userbo)
{
userbo->map = NULL;
}
void
nouveau_bo_emit_reloc(struct nouveau_channel *userchan, void *ptr,
struct nouveau_bo *userbo, uint32_t data, uint32_t flags,
uint32_t vor, uint32_t tor)
{
struct nouveau_channel_priv *chan = nouveau_channel(userchan);
struct nouveau_bo_priv *bo = nouveau_bo(userbo);
struct nouveau_bo_reloc *r;
int i, on_list = 0;
for (i = 0; i < chan->nr_buffers; i++) {
if (chan->buffers[i].bo == bo) {
on_list = 1;
break;
}
}
if (i >= 128)
return;
if (on_list) {
chan->buffers[i].flags &= (flags | NOUVEAU_BO_RDWR);
chan->buffers[i].flags |= (flags & NOUVEAU_BO_RDWR);
} else {
chan->buffers[i].bo = bo;
chan->buffers[i].flags = flags;
chan->nr_buffers++;
}
if (chan->num_relocs >= chan->max_relocs)
FIRE_RING_CH(userchan);
r = &chan->relocs[chan->num_relocs++];
r->ptr = ptr;
r->bo = bo;
r->data = data;
r->flags = flags;
r->vor = vor;
r->tor = tor;
}
static int
nouveau_bo_upload(struct nouveau_bo_priv *bo)
{
memcpy(bo->map, bo->sysmem, bo->drm.size);
return 0;
}
void
nouveau_bo_validate(struct nouveau_channel *userchan)
{
struct nouveau_channel_priv *chan = nouveau_channel(userchan);
int i;
for (i = 0; i < chan->nr_buffers; i++) {
struct nouveau_bo_priv *bo = chan->buffers[i].bo;
if (!bo->drm.size) {
nouveau_bo_realloc_gpu(bo, chan->buffers[i].flags,
bo->base.size);
nouveau_bo_upload(bo);
} else
if (bo->user || bo->base.map)
nouveau_bo_upload(bo);
if (!bo->user && !bo->base.map) {
free(bo->sysmem);
bo->sysmem = NULL;
}
bo->base.offset = bo->drm.offset;
if (bo->drm.flags & NOUVEAU_MEM_AGP)
bo->base.flags = NOUVEAU_BO_GART;
else
bo->base.flags = NOUVEAU_BO_VRAM;
}
chan->nr_buffers = 0;
}
@@ -0,0 +1,130 @@
/*
* Copyright 2007 Nouveau Project
*
* 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, sublicense,
* 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 above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* 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 NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS 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.
*/
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "nouveau_drmif.h"
#include "nouveau_dma.h"
int
nouveau_channel_alloc(struct nouveau_device *userdev, uint32_t fb_ctxdma,
uint32_t tt_ctxdma, struct nouveau_channel **userchan)
{
struct nouveau_device_priv *nv = nouveau_device(userdev);
struct nouveau_channel_priv *chan;
int ret;
if (!nv || !userchan || *userchan)
return -EINVAL;
chan = calloc(1, sizeof(*chan));
if (!chan)
return -ENOMEM;
chan->base.device = userdev;
chan->drm.fb_ctxdma_handle = fb_ctxdma;
chan->drm.tt_ctxdma_handle = tt_ctxdma;
ret = drmCommandWriteRead(nv->fd, DRM_NOUVEAU_CHANNEL_ALLOC,
&chan->drm, sizeof(chan->drm));
if (ret) {
free(chan);
return ret;
}
chan->base.id = chan->drm.channel;
if (nouveau_grobj_ref(&chan->base, chan->drm.fb_ctxdma_handle,
&chan->base.vram) ||
nouveau_grobj_ref(&chan->base, chan->drm.tt_ctxdma_handle,
&chan->base.gart)) {
nouveau_channel_free((void *)&chan);
return -EINVAL;
}
ret = drmMap(nv->fd, chan->drm.ctrl, chan->drm.ctrl_size,
(void*)&chan->user);
if (ret) {
nouveau_channel_free((void *)&chan);
return ret;
}
chan->put = &chan->user[0x40/4];
chan->get = &chan->user[0x44/4];
chan->ref_cnt = &chan->user[0x48/4];
ret = drmMap(nv->fd, chan->drm.notifier, chan->drm.notifier_size,
(drmAddressPtr)&chan->notifier_block);
if (ret) {
nouveau_channel_free((void *)&chan);
return ret;
}
ret = drmMap(nv->fd, chan->drm.cmdbuf, chan->drm.cmdbuf_size,
(void*)&chan->pushbuf);
if (ret) {
nouveau_channel_free((void *)&chan);
return ret;
}
chan->max_relocs = chan->drm.cmdbuf_size / 4;
chan->num_relocs = 0;
chan->relocs =
malloc(sizeof(struct nouveau_bo_reloc) * chan->max_relocs);
nouveau_dma_channel_init(&chan->base);
*userchan = &chan->base;
return 0;
}
void
nouveau_channel_free(struct nouveau_channel **userchan)
{
struct nouveau_channel_priv *chan;
if (!userchan)
return;
chan = nouveau_channel(*userchan);
if (chan) {
struct nouveau_device_priv *nv;
struct drm_nouveau_channel_free cf;
nv = nouveau_device((*userchan)->device);
*userchan = NULL;
FIRE_RING_CH(&chan->base);
if (chan->relocs)
free(chan->relocs);
nouveau_grobj_free(&chan->base.vram);
nouveau_grobj_free(&chan->base.gart);
cf.channel = chan->drm.channel;
drmCommandWrite(nv->fd, DRM_NOUVEAU_CHANNEL_FREE,
&cf, sizeof(cf));
free(chan);
}
}
@@ -0,0 +1,228 @@
#include "glheader.h"
#include "context.h"
#include "extensions.h"
#include "tnl/tnl.h"
#include "tnl/t_pipeline.h"
#include "tnl/t_vertex.h"
#include "drivers/common/driverfuncs.h"
#include "drirenderbuffer.h"
#include "state_tracker/st_public.h"
#include "state_tracker/st_context.h"
#include "pipe/p_defines.h"
#include "pipe/p_context.h"
#include "nouveau_context.h"
#include "nouveau_dri.h"
#include "nouveau_local.h"
#include "nouveau_screen.h"
#include "nouveau_winsys_pipe.h"
#define need_GL_ARB_fragment_program
#define need_GL_ARB_multisample
#define need_GL_ARB_occlusion_query
#define need_GL_ARB_texture_compression
#define need_GL_ARB_vertex_program
#define need_GL_ARB_vertex_buffer_object
#define need_GL_EXT_compiled_vertex_array
#define need_GL_EXT_fog_coord
#define need_GL_EXT_secondary_color
#define need_GL_EXT_framebuffer_object
#include "extension_helper.h"
const struct dri_extension common_extensions[] =
{
{ NULL, 0 }
};
const struct dri_extension nv40_extensions[] =
{
{ "GL_ARB_fragment_program", NULL },
{ "GL_ARB_multisample", GL_ARB_multisample_functions },
{ "GL_ARB_occlusion_query", GL_ARB_occlusion_query_functions },
{ "GL_ARB_texture_border_clamp", NULL },
{ "GL_ARB_texture_compression", GL_ARB_texture_compression_functions },
{ "GL_ARB_texture_cube_map", NULL },
{ "GL_ARB_texture_env_add", NULL },
{ "GL_ARB_texture_env_combine", NULL },
{ "GL_ARB_texture_env_crossbar", NULL },
{ "GL_ARB_texture_env_dot3", NULL },
{ "GL_ARB_texture_mirrored_repeat", NULL },
{ "GL_ARB_texture_non_power_of_two", NULL },
{ "GL_ARB_vertex_program", GL_ARB_vertex_program_functions },
{ "GL_ARB_vertex_buffer_object", GL_ARB_vertex_buffer_object_functions },
{ "GL_ATI_texture_env_combine3", NULL },
{ "GL_EXT_compiled_vertex_array", GL_EXT_compiled_vertex_array_functions },
{ "GL_EXT_fog_coord", GL_EXT_fog_coord_functions },
{ "GL_EXT_framebuffer_object", GL_EXT_framebuffer_object_functions },
{ "GL_EXT_secondary_color", GL_EXT_secondary_color_functions },
{ "GL_EXT_texture_edge_clamp", NULL },
{ "GL_EXT_texture_env_add", NULL },
{ "GL_EXT_texture_env_combine", NULL },
{ "GL_EXT_texture_env_dot3", NULL },
{ "GL_EXT_texture_mirror_clamp", NULL },
{ "GL_NV_texture_rectangle", NULL },
{ NULL, 0 }
};
#ifdef DEBUG
static const struct dri_debug_control debug_control[] = {
{ "bo", DEBUG_BO },
{ NULL, 0 }
};
int __nouveau_debug = 0;
#endif
GLboolean
nouveau_context_create(const __GLcontextModes *glVis,
__DRIcontextPrivate *driContextPriv,
void *sharedContextPrivate)
{
__DRIscreenPrivate *driScrnPriv = driContextPriv->driScreenPriv;
struct nouveau_screen *nv_screen = driScrnPriv->private;
struct nouveau_context *nv = CALLOC_STRUCT(nouveau_context);
struct nouveau_device_priv *nvdev;
struct pipe_context *pipe = NULL;
struct st_context *st_share = NULL;
int ret;
if (sharedContextPrivate) {
st_share = ((struct nouveau_context *)sharedContextPrivate)->st;
}
if ((ret = nouveau_device_get_param(nv_screen->device,
NOUVEAU_GETPARAM_CHIPSET_ID,
&nv->chipset))) {
NOUVEAU_ERR("Error determining chipset id: %d\n", ret);
return GL_FALSE;
}
if ((ret = nouveau_channel_alloc(nv_screen->device,
0x8003d001, 0x8003d002,
&nv->channel))) {
NOUVEAU_ERR("Error creating GPU channel: %d\n", ret);
return GL_FALSE;
}
driContextPriv->driverPrivate = (void *)nv;
nv->nv_screen = nv_screen;
nv->dri_screen = driScrnPriv;
nvdev = nouveau_device(nv_screen->device);
nvdev->ctx = driContextPriv->hHWContext;
nvdev->lock = (drmLock *)&driScrnPriv->pSAREA->lock;
driParseConfigFiles(&nv->dri_option_cache, &nv_screen->option_cache,
nv->dri_screen->myNum, "nouveau");
#ifdef DEBUG
__nouveau_debug = driParseDebugString(getenv("NOUVEAU_DEBUG"),
debug_control);
#endif
if ((ret = nouveau_grobj_alloc(nv->channel, 0x00000000, 0x30,
&nv->NvNull))) {
NOUVEAU_ERR("Error creating NULL object: %d\n", ret);
return GL_FALSE;
}
nv->next_handle = 0x80000000;
if ((ret = nouveau_notifier_alloc(nv->channel, nv->next_handle++, 1,
&nv->sync_notifier))) {
NOUVEAU_ERR("Error creating channel sync notifier: %d\n", ret);
return GL_FALSE;
}
if (nv->chipset < 0x50)
ret = nouveau_region_init_nv04(nv);
else
ret = nouveau_region_init_nv50(nv);
if (ret) {
return GL_FALSE;
}
if (!getenv("NOUVEAU_FORCE_SOFTPIPE")) {
pipe = nouveau_pipe_create(nv);
if (!pipe)
NOUVEAU_ERR("Couldn't create hw pipe\n");
}
if (!pipe) {
NOUVEAU_MSG("Using softpipe\n");
pipe = nouveau_create_softpipe(nv);
if (!pipe) {
NOUVEAU_ERR("Error creating pipe, bailing\n");
return GL_FALSE;
}
}
pipe->priv = nv;
nv->st = st_create_context(pipe, glVis, st_share);
return GL_TRUE;
}
void
nouveau_context_destroy(__DRIcontextPrivate *driContextPriv)
{
struct nouveau_context *nv = driContextPriv->driverPrivate;
assert(nv);
st_flush(nv->st, PIPE_FLUSH_WAIT);
st_destroy_context(nv->st);
nouveau_grobj_free(&nv->NvCtxSurf2D);
nouveau_grobj_free(&nv->NvImageBlit);
nouveau_channel_free(&nv->channel);
free(nv);
}
GLboolean
nouveau_context_bind(__DRIcontextPrivate *driContextPriv,
__DRIdrawablePrivate *driDrawPriv,
__DRIdrawablePrivate *driReadPriv)
{
struct nouveau_context *nv;
struct nouveau_framebuffer *draw, *read;
if (!driContextPriv) {
st_make_current(NULL, NULL, NULL);
return GL_TRUE;
}
nv = driContextPriv->driverPrivate;
draw = driDrawPriv->driverPrivate;
read = driReadPriv->driverPrivate;
st_make_current(nv->st, draw->stfb, read->stfb);
if ((nv->dri_drawable != driDrawPriv) ||
(nv->last_stamp != driDrawPriv->lastStamp)) {
nv->dri_drawable = driDrawPriv;
st_resize_framebuffer(draw->stfb, driDrawPriv->w,
driDrawPriv->h);
nv->last_stamp = driDrawPriv->lastStamp;
}
if (driDrawPriv != driReadPriv) {
st_resize_framebuffer(read->stfb, driReadPriv->w,
driReadPriv->h);
}
return GL_TRUE;
}
GLboolean
nouveau_context_unbind(__DRIcontextPrivate *driContextPriv)
{
struct nouveau_context *nv = driContextPriv->driverPrivate;
(void)nv;
st_flush(nv->st, 0);
return GL_TRUE;
}
@@ -0,0 +1,104 @@
#ifndef __NOUVEAU_CONTEXT_H__
#define __NOUVEAU_CONTEXT_H__
#include "glheader.h"
#include "context.h"
#include "dri_util.h"
#include "xmlconfig.h"
#include "pipe/nouveau/nouveau_winsys.h"
#include "nouveau_device.h"
#include "nouveau_drmif.h"
#include "nouveau_dma.h"
struct nouveau_framebuffer {
struct st_framebuffer *stfb;
};
struct nouveau_context {
struct st_context *st;
/* Misc HW info */
uint64_t chipset;
/* DRI stuff */
__DRIscreenPrivate *dri_screen;
__DRIdrawablePrivate *dri_drawable;
unsigned int last_stamp;
driOptionCache dri_option_cache;
drm_context_t drm_context;
drmLock drm_lock;
GLboolean locked;
struct nouveau_screen *nv_screen;
/* Bufmgr */
struct {
struct nouveau_channel *channel;
struct nouveau_notifier *notify;
struct nouveau_grobj *m2mf;
uint32_t m2mf_src_ctxdma;
uint32_t m2mf_dst_ctxdma;
uint32_t next_sequence;
} bo;
/* Relocations */
struct nouveau_bo *reloc_head;
/* Hardware context */
struct nouveau_channel *channel;
struct nouveau_notifier *sync_notifier;
struct nouveau_grobj *NvNull;
struct nouveau_grobj *NvCtxSurf2D;
struct nouveau_grobj *NvImageBlit;
struct nouveau_grobj *NvGdiRect;
uint32_t next_handle;
uint32_t next_sequence;
/* pipe_region accel */
int (*region_display)(void);
int (*region_copy)(struct nouveau_context *, struct pipe_region *,
unsigned, unsigned, unsigned, struct pipe_region *,
unsigned, unsigned, unsigned, unsigned, unsigned);
int (*region_fill)(struct nouveau_context *, struct pipe_region *,
unsigned, unsigned, unsigned, unsigned, unsigned,
unsigned);
int (*region_data)(struct nouveau_context *, struct pipe_region *,
unsigned, unsigned, unsigned, const void *,
unsigned, unsigned, unsigned, unsigned, unsigned);
};
static INLINE struct nouveau_context *
nouveau_context(GLcontext *ctx)
{
return (struct nouveau_context *)ctx;
}
extern GLboolean nouveau_context_create(const __GLcontextModes *,
__DRIcontextPrivate *, void *);
extern void nouveau_context_destroy(__DRIcontextPrivate *);
extern GLboolean nouveau_context_bind(__DRIcontextPrivate *,
__DRIdrawablePrivate *draw,
__DRIdrawablePrivate *read);
extern GLboolean nouveau_context_unbind(__DRIcontextPrivate *);
#ifdef DEBUG
extern int __nouveau_debug;
#define DEBUG_BO (1 << 0)
#define DBG(flag, ...) do { \
if (__nouveau_debug & (DEBUG_##flag)) \
NOUVEAU_ERR(__VA_ARGS__); \
} while(0)
#else
#define DBG(flag, ...)
#endif
extern void LOCK_HARDWARE(struct nouveau_context *);
extern void UNLOCK_HARDWARE(struct nouveau_context *);
extern int nouveau_region_init_nv04(struct nouveau_context *);
extern int nouveau_region_init_nv50(struct nouveau_context *);
#endif
@@ -0,0 +1,144 @@
/*
* Copyright 2007 Nouveau Project
*
* 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, sublicense,
* 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 above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* 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 NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include "nouveau_drmif.h"
int
nouveau_device_open_existing(struct nouveau_device **userdev, int close,
int fd, drm_context_t ctx)
{
struct nouveau_device_priv *nv;
int ret;
if (!userdev || *userdev)
return -EINVAL;
nv = calloc(1, sizeof(*nv));
if (!nv)
return -ENOMEM;
nv->fd = fd;
nv->ctx = ctx;
nv->needs_close = close;
drmCommandNone(nv->fd, DRM_NOUVEAU_CARD_INIT);
if ((ret = nouveau_bo_init(&nv->base))) {
nouveau_device_close((void *)&nv);
return ret;
}
*userdev = &nv->base;
return 0;
}
int
nouveau_device_open(struct nouveau_device **userdev, const char *busid)
{
drm_context_t ctx;
int fd, ret;
if (!userdev || *userdev)
return -EINVAL;
fd = drmOpen("nouveau", busid);
if (fd < 0)
return -EINVAL;
ret = drmCreateContext(fd, &ctx);
if (ret) {
drmClose(fd);
return ret;
}
ret = nouveau_device_open_existing(userdev, 1, fd, ctx);
if (ret) {
drmDestroyContext(fd, ctx);
drmClose(fd);
return ret;
}
return 0;
}
void
nouveau_device_close(struct nouveau_device **userdev)
{
struct nouveau_device_priv *nv;
if (userdev || !*userdev)
return;
nv = (struct nouveau_device_priv *)*userdev;
*userdev = NULL;
nouveau_bo_takedown(&nv->base);
if (nv->needs_close) {
drmDestroyContext(nv->fd, nv->ctx);
drmClose(nv->fd);
}
free(nv);
}
int
nouveau_device_get_param(struct nouveau_device *userdev,
uint64_t param, uint64_t *value)
{
struct nouveau_device_priv *nv = (struct nouveau_device_priv *)userdev;
struct drm_nouveau_getparam g;
int ret;
if (!nv || !value)
return -EINVAL;
g.param = param;
ret = drmCommandWriteRead(nv->fd, DRM_NOUVEAU_GETPARAM, &g, sizeof(g));
if (ret)
return ret;
*value = g.value;
return 0;
}
int
nouveau_device_set_param(struct nouveau_device *userdev,
uint64_t param, uint64_t value)
{
struct nouveau_device_priv *nv = (struct nouveau_device_priv *)userdev;
struct drm_nouveau_setparam s;
int ret;
if (!nv)
return -EINVAL;
s.param = param;
s.value = value;
ret = drmCommandWriteRead(nv->fd, DRM_NOUVEAU_SETPARAM, &s, sizeof(s));
if (ret)
return ret;
return 0;
}
@@ -0,0 +1,29 @@
/*
* Copyright 2007 Nouveau Project
*
* 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, sublicense,
* 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 above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* 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 NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS 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.
*/
#ifndef __NOUVEAU_DEVICE_H__
#define __NOUVEAU_DEVICE_H__
struct nouveau_device {
};
#endif
@@ -0,0 +1,193 @@
/*
* Copyright 2007 Nouveau Project
*
* 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, sublicense,
* 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 above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* 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 NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS 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.
*/
#include <stdint.h>
#include <assert.h>
#include <errno.h>
#include "nouveau_drmif.h"
#include "nouveau_dma.h"
#include "nouveau_local.h"
#define READ_GET(ch) ((*(ch)->get - (ch)->dma.base) >> 2)
#define WRITE_PUT(ch, val) do { \
volatile int dum; \
NOUVEAU_DMA_BARRIER; \
dum=READ_GET(ch); \
*(ch)->put = (((val) << 2) + (ch)->dma.base); \
NOUVEAU_DMA_BARRIER; \
} while(0)
void
nouveau_dma_channel_init(struct nouveau_channel *userchan)
{
struct nouveau_channel_priv *chan = nouveau_channel(userchan);
int i;
chan->dma.base = chan->drm.put_base;
chan->dma.cur = chan->dma.put = RING_SKIPS;
chan->dma.max = (chan->drm.cmdbuf_size >> 2) - 2;
chan->dma.free = chan->dma.max - chan->dma.cur;
for (i = 0; i < RING_SKIPS; i++)
chan->pushbuf[i] = 0x00000000;
}
#define CHECK_TIMEOUT() do { \
if ((NOUVEAU_TIME_MSEC() - t_start) > NOUVEAU_DMA_TIMEOUT) \
return - EBUSY; \
} while(0)
int
nouveau_dma_wait(struct nouveau_channel *userchan, int size)
{
struct nouveau_channel_priv *chan = nouveau_channel(userchan);
uint32_t get, t_start;
FIRE_RING_CH(userchan);
t_start = NOUVEAU_TIME_MSEC();
while (chan->dma.free < size) {
get = READ_GET(chan);
if (chan->dma.put >= get) {
chan->dma.free = chan->dma.max - chan->dma.cur;
if (chan->dma.free < size) {
#ifdef NOUVEAU_DMA_DEBUG
chan->dma.push_free = 1;
#endif
OUT_RING_CH(userchan,
0x20000000 | chan->dma.base);
if (get <= RING_SKIPS) {
/*corner case - will be idle*/
if (chan->dma.put <= RING_SKIPS)
WRITE_PUT(chan, RING_SKIPS + 1);
do {
CHECK_TIMEOUT();
get = READ_GET(chan);
} while (get <= RING_SKIPS);
}
WRITE_PUT(chan, RING_SKIPS);
chan->dma.cur = chan->dma.put = RING_SKIPS;
chan->dma.free = get - (RING_SKIPS + 1);
}
} else {
chan->dma.free = get - chan->dma.cur - 1;
}
CHECK_TIMEOUT();
}
return 0;
}
#ifdef NOUVEAU_DMA_SUBCHAN_LRU
void
nouveau_dma_subc_bind(struct nouveau_grobj *grobj)
{
struct nouveau_channel_priv *chan = nouveau_channel(grobj->channel);
int subc = -1, i;
for (i = 0; i < 8; i++) {
if (chan->subchannel[i].grobj &&
chan->subchannel[i].grobj->bound ==
NOUVEAU_GROBJ_EXPLICIT_BIND)
continue;
if (chan->subchannel[i].seq < chan->subchannel[subc].seq)
subc = i;
}
assert(subc >= 0);
if (chan->subchannel[subc].grobj)
chan->subchannel[subc].grobj->bound = 0;
chan->subchannel[subc].grobj = grobj;
grobj->subc = subc;
grobj->bound = NOUVEAU_GROBJ_BOUND;
BEGIN_RING_CH(grobj->channel, grobj, 0, 1);
nouveau_dma_out (grobj->channel, grobj->handle);
}
#endif
void
nouveau_dma_kickoff(struct nouveau_channel *userchan)
{
struct nouveau_channel_priv *chan = nouveau_channel(userchan);
uint32_t put_offset;
int i;
if (chan->dma.cur == chan->dma.put)
return;
if (chan->num_relocs) {
nouveau_bo_validate(userchan);
for (i = 0; i < chan->num_relocs; i++) {
struct nouveau_bo_reloc *r = &chan->relocs[i];
uint32_t push;
if (r->flags & NOUVEAU_BO_LOW) {
push = r->bo->base.offset + r->data;
} else
if (r->flags & NOUVEAU_BO_HIGH) {
push = (r->bo->base.offset + r->data) >> 32;
} else {
push = r->data;
}
if (r->flags & NOUVEAU_BO_OR) {
if (r->bo->base.flags & NOUVEAU_BO_VRAM)
push |= r->vor;
else
push |= r->tor;
}
*r->ptr = push;
}
chan->num_relocs = 0;
}
#ifdef NOUVEAU_DMA_DEBUG
if (chan->dma.push_free) {
NOUVEAU_ERR("Packet incomplete: %d left\n", chan->dma.push_free);
return;
}
#endif
#ifdef NOUVEAU_DMA_DUMP_POSTRELOC_PUSHBUF
for (i = chan->dma.put; i < chan->dma.cur; i++)
NOUVEAU_MSG("0x%08x\n", chan->pushbuf[i]);
#endif
put_offset = (chan->dma.cur << 2) + chan->dma.base;
#ifdef NOUVEAU_DMA_TRACE
NOUVEAU_MSG("FIRE_RING %d/0x%08x\n", chan->drm.channel, put_offset);
#endif
chan->dma.put = chan->dma.cur;
NOUVEAU_DMA_BARRIER;
*chan->put = put_offset;
NOUVEAU_DMA_BARRIER;
}
@@ -0,0 +1,158 @@
/*
* Copyright 2007 Nouveau Project
*
* 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, sublicense,
* 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 above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* 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 NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS 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.
*/
#ifndef __NOUVEAU_DMA_H__
#define __NOUVEAU_DMA_H__
#include <string.h>
#include "nouveau_drmif.h"
#include "nouveau_local.h"
#define RING_SKIPS 8
extern int nouveau_dma_wait(struct nouveau_channel *chan, int size);
extern void nouveau_dma_subc_bind(struct nouveau_grobj *);
extern void nouveau_dma_channel_init(struct nouveau_channel *);
extern void nouveau_dma_kickoff(struct nouveau_channel *);
#ifdef NOUVEAU_DMA_DEBUG
static char faulty[1024];
#endif
static inline void
nouveau_dma_out(struct nouveau_channel *userchan, uint32_t data)
{
struct nouveau_channel_priv *chan = nouveau_channel(userchan);
#ifdef NOUVEAU_DMA_DEBUG
if (chan->dma.push_free == 0) {
NOUVEAU_ERR("No space left in packet. Error at %s\n",faulty);
return;
}
chan->dma.push_free--;
#endif
#ifdef NOUVEAU_DMA_TRACE
{
uint32_t offset = (chan->dma.cur << 2) + chan->dma.base;
NOUVEAU_MSG("\tOUT_RING %d/0x%08x -> 0x%08x\n",
chan->drm.channel, offset, data);
}
#endif
chan->pushbuf[chan->dma.cur++] = data;
}
static inline void
nouveau_dma_outp(struct nouveau_channel *userchan, uint32_t *ptr, int size)
{
struct nouveau_channel_priv *chan = nouveau_channel(userchan);
(void)chan;
#ifdef NOUVEAU_DMA_DEBUG
if (chan->dma.push_free < size) {
NOUVEAU_ERR("Packet too small. Free=%d, Need=%d\n",
chan->dma.push_free, size);
return;
}
#endif
#ifdef NOUVEAU_DMA_TRACE
while (size--) {
nouveau_dma_out(userchan, *ptr);
ptr++;
}
#else
memcpy(&chan->pushbuf[chan->dma.cur], ptr, size << 2);
#ifdef NOUVEAU_DMA_DEBUG
chan->dma.push_free -= size;
#endif
chan->dma.cur += size;
#endif
}
static inline void
nouveau_dma_begin(struct nouveau_channel *userchan, struct nouveau_grobj *grobj,
int method, int size, const char* file, int line)
{
struct nouveau_channel_priv *chan = nouveau_channel(userchan);
int push_size = size + 1;
#ifdef NOUVEAU_DMA_SUBCHAN_LRU
if (grobj->bound == NOUVEAU_GROBJ_UNBOUND)
nouveau_dma_subc_bind(grobj);
chan->subchannel[grobj->subc].seq = chan->subc_sequence++;
#endif
#ifdef NOUVEAU_DMA_TRACE
NOUVEAU_MSG("BEGIN_RING %d/%08x/%d/0x%04x/%d\n", chan->drm.channel,
grobj->handle, grobj->subc, method, size);
#endif
#ifdef NOUVEAU_DMA_DEBUG
if (chan->dma.push_free) {
NOUVEAU_ERR("Previous packet incomplete: %d left. Error at %s\n",
chan->dma.push_free,faulty);
return;
}
sprintf(faulty,"%s:%d",file,line);
#endif
if (chan->dma.free < push_size) {
if (nouveau_dma_wait(userchan, push_size) &&
userchan->hang_notify) {
userchan->hang_notify(userchan);
}
}
chan->dma.free -= push_size;
#ifdef NOUVEAU_DMA_DEBUG
chan->dma.push_free = push_size;
#endif
nouveau_dma_out(userchan, (size << 18) | (grobj->subc << 13) | method);
}
static inline void
nouveau_dma_bind(struct nouveau_channel *userchan, struct nouveau_grobj *grobj,
int subc)
{
struct nouveau_channel_priv *chan = nouveau_channel(userchan);
if (chan->subchannel[subc].grobj == grobj)
return;
if (chan->subchannel[subc].grobj)
chan->subchannel[subc].grobj->bound = NOUVEAU_GROBJ_UNBOUND;
chan->subchannel[subc].grobj = grobj;
grobj->subc = subc;
grobj->bound = NOUVEAU_GROBJ_EXPLICIT_BIND;
nouveau_dma_begin(userchan, grobj, 0x0000, 1, __FUNCTION__, __LINE__);
nouveau_dma_out (userchan, grobj->handle);
}
#define BIND_RING_CH(ch,gr,sc) nouveau_dma_bind((ch), (gr), (sc))
#define BEGIN_RING_CH(ch,gr,m,sz) nouveau_dma_begin((ch), (gr), (m), (sz), __FUNCTION__, __LINE__ )
#define OUT_RING_CH(ch, data) nouveau_dma_out((ch), (data))
#define OUT_RINGp_CH(ch,ptr,dwords) nouveau_dma_outp((ch), (void*)(ptr), \
(dwords))
#define FIRE_RING_CH(ch) nouveau_dma_kickoff((ch))
#define WAIT_RING_CH(ch,sz) nouveau_dma_wait((ch), (sz))
#endif
@@ -0,0 +1,28 @@
#ifndef _NOUVEAU_DRI_
#define _NOUVEAU_DRI_
#include "xf86drm.h"
#include "drm.h"
#include "nouveau_drm.h"
struct nouveau_dri {
uint32_t device_id; /**< \brief PCI device ID */
uint32_t width; /**< \brief width in pixels of display */
uint32_t height; /**< \brief height in scanlines of display */
uint32_t depth; /**< \brief depth of display (8, 15, 16, 24) */
uint32_t bpp; /**< \brief bit depth of display (8, 16, 24, 32) */
uint32_t bus_type; /**< \brief ths bus type */
uint32_t bus_mode; /**< \brief bus mode (used for AGP, maybe also for PCI-E ?) */
uint32_t front_offset; /**< \brief front buffer offset */
uint32_t front_pitch; /**< \brief front buffer pitch */
uint32_t back_offset; /**< \brief private back buffer offset */
uint32_t back_pitch; /**< \brief private back buffer pitch */
uint32_t depth_offset; /**< \brief private depth buffer offset */
uint32_t depth_pitch; /**< \brief private depth buffer pitch */
};
#endif
@@ -0,0 +1,212 @@
/*
* Copyright 2007 Nouveau Project
*
* 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, sublicense,
* 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 above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* 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 NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS 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.
*/
#ifndef __NOUVEAU_DRMIF_H__
#define __NOUVEAU_DRMIF_H__
#include <stdint.h>
#include <xf86drm.h>
#include <nouveau_drm.h>
#include "nouveau_device.h"
#include "pipe/nouveau/nouveau_channel.h"
#include "pipe/nouveau/nouveau_grobj.h"
#include "pipe/nouveau/nouveau_notifier.h"
#include "pipe/nouveau/nouveau_bo.h"
struct nouveau_device_priv {
struct nouveau_device base;
int fd;
drm_context_t ctx;
drmLock *lock;
int needs_close;
struct {
struct nouveau_channel *channel;
struct nouveau_notifier *notify;
struct nouveau_grobj *m2mf;
} bufmgr;
};
#define nouveau_device(n) ((struct nouveau_device_priv *)(n))
extern int
nouveau_device_open_existing(struct nouveau_device **, int close,
int fd, drm_context_t ctx);
extern int
nouveau_device_open(struct nouveau_device **, const char *busid);
extern void
nouveau_device_close(struct nouveau_device **);
extern int
nouveau_device_get_param(struct nouveau_device *, uint64_t param, uint64_t *v);
extern int
nouveau_device_set_param(struct nouveau_device *, uint64_t param, uint64_t val);
struct nouveau_channel_priv {
struct nouveau_channel base;
struct drm_nouveau_channel_alloc drm;
struct {
struct nouveau_grobj *grobj;
uint32_t seq;
} subchannel[8];
uint32_t subc_sequence;
uint32_t *pushbuf;
void *notifier_block;
volatile uint32_t *user;
volatile uint32_t *put;
volatile uint32_t *get;
volatile uint32_t *ref_cnt;
struct {
uint32_t base, max;
uint32_t cur, put;
uint32_t free;
int push_free;
} dma;
struct {
struct nouveau_bo_priv *bo;
uint32_t flags;
} buffers[128];
int nr_buffers;
struct nouveau_bo_reloc *relocs;
int num_relocs;
int max_relocs;
};
#define nouveau_channel(n) ((struct nouveau_channel_priv *)(n))
extern int
nouveau_channel_alloc(struct nouveau_device *, uint32_t fb, uint32_t tt,
struct nouveau_channel **);
extern void
nouveau_channel_free(struct nouveau_channel **);
struct nouveau_grobj_priv {
struct nouveau_grobj base;
};
#define nouveau_grobj(n) ((struct nouveau_grobj_priv *)(n))
extern int nouveau_grobj_alloc(struct nouveau_channel *, uint32_t handle,
int class, struct nouveau_grobj **);
extern int nouveau_grobj_ref(struct nouveau_channel *, uint32_t handle,
struct nouveau_grobj **);
extern void nouveau_grobj_free(struct nouveau_grobj **);
struct nouveau_notifier_priv {
struct nouveau_notifier base;
struct drm_nouveau_notifierobj_alloc drm;
volatile void *map;
};
#define nouveau_notifier(n) ((struct nouveau_notifier_priv *)(n))
extern int
nouveau_notifier_alloc(struct nouveau_channel *, uint32_t handle, int count,
struct nouveau_notifier **);
extern void
nouveau_notifier_free(struct nouveau_notifier **);
extern void
nouveau_notifier_reset(struct nouveau_notifier *, int id);
extern uint32_t
nouveau_notifier_status(struct nouveau_notifier *, int id);
extern uint32_t
nouveau_notifier_return_val(struct nouveau_notifier *, int id);
extern int
nouveau_notifier_wait_status(struct nouveau_notifier *, int id, int status,
int timeout);
struct nouveau_bo_priv {
struct nouveau_bo base;
struct drm_nouveau_mem_alloc drm;
void *map;
void *sysmem;
int user;
int refcount;
};
struct nouveau_bo_reloc {
struct nouveau_bo_priv *bo;
uint32_t *ptr;
uint32_t flags;
uint32_t data, vor, tor;
};
#define nouveau_bo(n) ((struct nouveau_bo_priv *)(n))
extern int
nouveau_bo_init(struct nouveau_device *);
extern void
nouveau_bo_takedown(struct nouveau_device *);
extern int
nouveau_bo_new(struct nouveau_device *, uint32_t flags, int align, int size,
struct nouveau_bo **);
extern int
nouveau_bo_user(struct nouveau_device *, void *ptr, int size,
struct nouveau_bo **);
extern int
nouveau_bo_ref(struct nouveau_device *, uint64_t handle, struct nouveau_bo **);
extern int
nouveau_bo_resize(struct nouveau_bo *, int size);
extern void
nouveau_bo_del(struct nouveau_bo **);
extern int
nouveau_bo_map(struct nouveau_bo *, uint32_t flags);
extern void
nouveau_bo_unmap(struct nouveau_bo *);
extern void
nouveau_bo_emit_reloc(struct nouveau_channel *chan, void *ptr,
struct nouveau_bo *, uint32_t data, uint32_t flags,
uint32_t vor, uint32_t tor);
extern void
nouveau_bo_validate(struct nouveau_channel *);
#endif
@@ -0,0 +1,107 @@
/*
* Copyright 2007 Nouveau Project
*
* 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, sublicense,
* 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 above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* 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 NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS 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.
*/
#include <stdlib.h>
#include <errno.h>
#include "nouveau_drmif.h"
int
nouveau_grobj_alloc(struct nouveau_channel *userchan, uint32_t handle,
int class, struct nouveau_grobj **usergrobj)
{
struct nouveau_device_priv *nv = nouveau_device(userchan->device);
struct nouveau_grobj_priv *gr;
struct drm_nouveau_grobj_alloc g;
int ret;
if (!nv || !usergrobj || *usergrobj)
return -EINVAL;
gr = calloc(1, sizeof(*gr));
if (!gr)
return -ENOMEM;
gr->base.channel = userchan;
gr->base.handle = handle;
gr->base.grclass = class;
g.channel = userchan->id;
g.handle = handle;
g.class = class;
ret = drmCommandWrite(nv->fd, DRM_NOUVEAU_GROBJ_ALLOC, &g, sizeof(g));
if (ret) {
nouveau_grobj_free((void *)&gr);
return ret;
}
*usergrobj = &gr->base;
return 0;
}
int
nouveau_grobj_ref(struct nouveau_channel *userchan, uint32_t handle,
struct nouveau_grobj **usergr)
{
struct nouveau_grobj_priv *gr;
if (!userchan || !usergr || *usergr)
return -EINVAL;
gr = calloc(1, sizeof(*gr));
if (!gr)
return -ENOMEM;
gr->base.channel = userchan;
gr->base.handle = handle;
gr->base.grclass = 0;
*usergr = &gr->base;
return 0;
}
void
nouveau_grobj_free(struct nouveau_grobj **usergrobj)
{
struct nouveau_grobj_priv *gr;
if (!usergrobj)
return;
gr = nouveau_grobj(*usergrobj);
*usergrobj = NULL;
if (gr) {
struct nouveau_channel_priv *chan;
struct nouveau_device_priv *nv;
struct drm_nouveau_gpuobj_free f;
chan = nouveau_channel(gr->base.channel);
nv = nouveau_device(chan->base.device);
if (gr->base.grclass) {
f.channel = chan->drm.channel;
f.handle = gr->base.handle;
drmCommandWrite(nv->fd, DRM_NOUVEAU_GPUOBJ_FREE,
&f, sizeof(f));
}
free(gr);
}
}
@@ -0,0 +1,82 @@
#ifndef __NOUVEAU_LOCAL_H__
#define __NOUVEAU_LOCAL_H__
#include <stdio.h>
/* Debug output */
#define NOUVEAU_MSG(fmt, args...) do { \
fprintf(stdout, "nouveau: "fmt, ##args); \
fflush(stdout); \
} while(0)
#define NOUVEAU_ERR(fmt, args...) do { \
fprintf(stderr, "%s:%d - "fmt, __func__, __LINE__, ##args); \
fflush(stderr); \
} while(0)
#define NOUVEAU_TIME_MSEC() 0
/* User FIFO control */
//#define NOUVEAU_DMA_TRACE
//#define NOUVEAU_DMA_DEBUG
//#define NOUVEAU_DMA_DUMP_POSTRELOC_PUSHBUF
#define NOUVEAU_DMA_SUBCHAN_LRU
#define NOUVEAU_DMA_BARRIER
#define NOUVEAU_DMA_TIMEOUT 2000
/* Push buffer access macros */
#define BEGIN_RING(obj,mthd,size) do { \
BEGIN_RING_CH(nv->channel, nv->obj, (mthd), (size)); \
} while(0)
#define OUT_RING(data) do { \
OUT_RING_CH(nv->channel, (data)); \
} while(0)
#define OUT_RINGp(src,size) do { \
OUT_RINGp_CH(nv->channel, (src), (size)); \
} while(0)
#define OUT_RINGf(data) do { \
union { float v; uint32_t u; } c; \
c.v = (data); \
OUT_RING(c.u); \
} while(0)
#define WAIT_RING(size) do { \
WAIT_RING_CH(nv->channel, (size)); \
} while(0)
#define FIRE_RING() do { \
FIRE_RING_CH(nv->channel); \
} while(0)
#define OUT_RELOC(bo,data,flags,vor,tor) do { \
struct nouveau_channel_priv *chan = nouveau_channel(nv->channel); \
nouveau_bo_emit_reloc(nv->channel, &chan->pushbuf[chan->dma.cur], \
(void*)(bo), (data), (flags), (vor), (tor)); \
OUT_RING(0); \
} while(0)
/* Raw data + flags depending on FB/TT buffer */
#define OUT_RELOCd(bo,data,flags,vor,tor) do { \
OUT_RELOC((bo), (data), (flags) | NOUVEAU_BO_OR, (vor), (tor)); \
} while(0)
/* FB/TT object handle */
#define OUT_RELOCo(bo,flags) do { \
OUT_RELOC((bo), 0, (flags) | NOUVEAU_BO_OR, \
nv->channel->vram->handle, nv->channel->gart->handle); \
} while(0)
/* Low 32-bits of offset */
#define OUT_RELOCl(bo,delta,flags) do { \
OUT_RELOC((bo), (delta), (flags) | NOUVEAU_BO_LOW, 0, 0); \
} while(0)
/* High 32-bits of offset */
#define OUT_RELOCh(bo,delta,flags) do { \
OUT_RELOC((bo), (delta), (flags) | NOUVEAU_BO_HIGH, 0, 0); \
} while(0)
#endif
@@ -0,0 +1,103 @@
/**************************************************************************
*
* Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
* 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 above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* 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 TUNGSTEN GRAPHICS 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.
*
**************************************************************************/
#include "glheader.h"
#include "context.h"
#include "extensions.h"
#include "state_tracker/st_public.h"
#include "state_tracker/st_context.h"
#include "drirenderbuffer.h"
#include "vblank.h"
#include "utils.h"
#include "xmlpool.h" /* for symbolic values of enum-type options */
#include "nouveau_context.h"
#include "nouveau_screen.h"
_glthread_DECLARE_STATIC_MUTEX( lockMutex );
static void
nouveau_contended_lock(struct nouveau_context *nv, GLuint flags)
{
__DRIdrawablePrivate *dPriv = nv->dri_drawable;
__DRIscreenPrivate *sPriv = nv->dri_screen;
struct nouveau_screen *nv_screen = nv->nv_screen;
struct nouveau_device *dev = nv_screen->device;
struct nouveau_device_priv *nvdev = nouveau_device(dev);
drmGetLock(nvdev->fd, nvdev->ctx, flags);
/* If the window moved, may need to set a new cliprect now.
*
* NOTE: This releases and regains the hw lock, so all state
* checking must be done *after* this call:
*/
if (dPriv)
DRI_VALIDATE_DRAWABLE_INFO(sPriv, dPriv);
}
/* Lock the hardware and validate our state.
*/
void
LOCK_HARDWARE(struct nouveau_context *nv)
{
struct nouveau_screen *nv_screen = nv->nv_screen;
struct nouveau_device *dev = nv_screen->device;
struct nouveau_device_priv *nvdev = nouveau_device(dev);
char __ret=0;
_glthread_LOCK_MUTEX(lockMutex);
assert(!nv->locked);
DRM_CAS(nvdev->lock, nvdev->ctx,
(DRM_LOCK_HELD | nvdev->ctx), __ret);
if (__ret)
nouveau_contended_lock(nv, 0);
nv->locked = GL_TRUE;
}
/* Unlock the hardware using the global current context
*/
void
UNLOCK_HARDWARE(struct nouveau_context *nv)
{
struct nouveau_screen *nv_screen = nv->nv_screen;
struct nouveau_device *dev = nv_screen->device;
struct nouveau_device_priv *nvdev = nouveau_device(dev);
assert(nv->locked);
nv->locked = GL_FALSE;
DRM_UNLOCK(nvdev->fd, nvdev->lock, nvdev->ctx);
_glthread_UNLOCK_MUTEX(lockMutex);
}
@@ -0,0 +1,140 @@
/*
* Copyright 2007 Nouveau Project
*
* 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, sublicense,
* 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 above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* 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 NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS 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.
*/
#include <stdlib.h>
#include <errno.h>
#include "nouveau_drmif.h"
#include "nouveau_local.h"
#define NOTIFIER(__v) \
struct nouveau_notifier_priv *notifier = nouveau_notifier(user); \
volatile uint32_t *n = (void*)notifier->map + (id * 32)
int
nouveau_notifier_alloc(struct nouveau_channel *userchan, uint32_t handle,
int count, struct nouveau_notifier **usernotifier)
{
struct nouveau_notifier_priv *notifier;
int ret;
if (!userchan || !usernotifier || *usernotifier)
return -EINVAL;
notifier = calloc(1, sizeof(*notifier));
if (!notifier)
return -ENOMEM;
notifier->base.channel = userchan;
notifier->base.handle = handle;
notifier->drm.channel = userchan->id;
notifier->drm.handle = handle;
notifier->drm.count = count;
if ((ret = drmCommandWriteRead(nouveau_device(userchan->device)->fd,
DRM_NOUVEAU_NOTIFIEROBJ_ALLOC,
&notifier->drm,
sizeof(notifier->drm)))) {
nouveau_notifier_free((void *)&notifier);
return ret;
}
notifier->map = (void *)nouveau_channel(userchan)->notifier_block +
notifier->drm.offset;
*usernotifier = &notifier->base;
return 0;
}
void
nouveau_notifier_free(struct nouveau_notifier **usernotifier)
{
struct nouveau_notifier_priv *notifier;
if (!usernotifier)
return;
notifier = nouveau_notifier(*usernotifier);
*usernotifier = NULL;
if (notifier) {
struct nouveau_channel_priv *chan;
struct nouveau_device_priv *nv;
struct drm_nouveau_gpuobj_free f;
chan = nouveau_channel(notifier->base.channel);
nv = nouveau_device(chan->base.device);
f.channel = chan->drm.channel;
f.handle = notifier->base.handle;
drmCommandWrite(nv->fd, DRM_NOUVEAU_GPUOBJ_FREE, &f, sizeof(f));
free(notifier);
}
}
void
nouveau_notifier_reset(struct nouveau_notifier *user, int id)
{
NOTIFIER(n);
n[NV_NOTIFY_TIME_0 /4] = 0x00000000;
n[NV_NOTIFY_TIME_1 /4] = 0x00000000;
n[NV_NOTIFY_RETURN_VALUE/4] = 0x00000000;
n[NV_NOTIFY_STATE /4] = (NV_NOTIFY_STATE_STATUS_IN_PROCESS <<
NV_NOTIFY_STATE_STATUS_SHIFT);
}
uint32_t
nouveau_notifier_status(struct nouveau_notifier *user, int id)
{
NOTIFIER(n);
return n[NV_NOTIFY_STATE/4] >> NV_NOTIFY_STATE_STATUS_SHIFT;
}
uint32_t
nouveau_notifier_return_val(struct nouveau_notifier *user, int id)
{
NOTIFIER(n);
return n[NV_NOTIFY_RETURN_VALUE/4];
}
int
nouveau_notifier_wait_status(struct nouveau_notifier *user, int id,
int status, int timeout)
{
NOTIFIER(n);
uint32_t time = 0, t_start = NOUVEAU_TIME_MSEC();
while (time <= timeout) {
uint32_t v;
v = n[NV_NOTIFY_STATE/4] >> NV_NOTIFY_STATE_STATUS_SHIFT;
if (v == status)
return 0;
if (timeout)
time = NOUVEAU_TIME_MSEC() - t_start;
}
return -EBUSY;
}
@@ -0,0 +1,253 @@
#include "glheader.h"
#include "context.h"
#include "framebuffer.h"
#include "matrix.h"
#include "renderbuffer.h"
#include "simple_list.h"
#include "utils.h"
#include "vblank.h"
#include "xmlpool.h"
#include "pipe/p_context.h"
#include "state_tracker/st_public.h"
#include "state_tracker/st_cb_fbo.h"
#include "nouveau_context.h"
#include "nouveau_device.h"
#include "nouveau_drm.h"
#include "nouveau_dri.h"
#include "nouveau_local.h"
#include "nouveau_screen.h"
#include "nouveau_swapbuffers.h"
#if NOUVEAU_DRM_HEADER_PATCHLEVEL != 10
#error nouveau_drm.h version does not match expected version
#endif
PUBLIC const char __driConfigOptions[] =
DRI_CONF_BEGIN
DRI_CONF_END;
static const GLuint __driNConfigOptions = 0;
extern const struct dri_extension common_extensions[];
extern const struct dri_extension nv40_extensions[];
static GLboolean
nouveau_screen_create(__DRIscreenPrivate *driScrnPriv)
{
struct nouveau_dri *nv_dri = driScrnPriv->pDevPriv;
struct nouveau_screen *nv_screen;
int ret;
if (driScrnPriv->devPrivSize != sizeof(struct nouveau_dri)) {
NOUVEAU_ERR("DRI struct mismatch between DDX/DRI\n");
return GL_FALSE;
}
nv_screen = CALLOC_STRUCT(nouveau_screen);
if (!nv_screen)
return GL_FALSE;
nv_screen->driScrnPriv = driScrnPriv;
driScrnPriv->private = (void *)nv_screen;
driParseOptionInfo(&nv_screen->option_cache,
__driConfigOptions, __driNConfigOptions);
if ((ret = nouveau_device_open_existing(&nv_screen->device, 0,
driScrnPriv->fd, 0))) {
NOUVEAU_ERR("Failed opening nouveau device: %d\n", ret);
return GL_FALSE;
}
nv_screen->front_offset = nv_dri->front_offset;
nv_screen->front_pitch = nv_dri->front_pitch * (nv_dri->bpp / 8);
return GL_TRUE;
}
static void
nouveau_screen_destroy(__DRIscreenPrivate *driScrnPriv)
{
struct nouveau_screen *nv_screen = driScrnPriv->private;
driScrnPriv->private = NULL;
FREE(nv_screen);
}
static GLboolean
nouveau_create_buffer(__DRIscreenPrivate * driScrnPriv,
__DRIdrawablePrivate * driDrawPriv,
const __GLcontextModes *glVis, GLboolean pixmapBuffer)
{
struct nouveau_framebuffer *nvfb;
if (pixmapBuffer)
return GL_FALSE;
nvfb = CALLOC_STRUCT(nouveau_framebuffer);
if (!nvfb)
return GL_FALSE;
nvfb->stfb = st_create_framebuffer(glVis, GL_TRUE, (void*)nvfb);
if (!nvfb->stfb) {
free(nvfb);
return GL_FALSE;
}
driDrawPriv->driverPrivate = (void *)nvfb;
return GL_TRUE;
}
static void
nouveau_destroy_buffer(__DRIdrawablePrivate * driDrawPriv)
{
struct nouveau_framebuffer *nvfb;
nvfb = (struct nouveau_framebuffer *)driDrawPriv;
st_unreference_framebuffer(&nvfb->stfb);
free(nvfb);
}
static struct __DriverAPIRec
nouveau_api = {
.InitDriver = nouveau_screen_create,
.DestroyScreen = nouveau_screen_destroy,
.CreateContext = nouveau_context_create,
.DestroyContext = nouveau_context_destroy,
.CreateBuffer = nouveau_create_buffer,
.DestroyBuffer = nouveau_destroy_buffer,
.SwapBuffers = nouveau_swap_buffers,
.MakeCurrent = nouveau_context_bind,
.UnbindContext = nouveau_context_unbind,
.GetSwapInfo = NULL,
.GetMSC = NULL,
.WaitForMSC = NULL,
.WaitForSBC = NULL,
.SwapBuffersMSC = NULL,
.CopySubBuffer = nouveau_copy_sub_buffer,
.setTexOffset = NULL
};
static __GLcontextModes *
nouveau_fill_in_modes(unsigned pixel_bits, unsigned depth_bits,
unsigned stencil_bits, GLboolean have_back_buffer)
{
__GLcontextModes * modes;
__GLcontextModes * m;
unsigned num_modes;
unsigned depth_buffer_factor;
unsigned back_buffer_factor;
int i;
static const struct {
GLenum format;
GLenum type;
} fb_format_array[] = {
{ GL_RGB , GL_UNSIGNED_SHORT_5_6_5 },
{ GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV },
{ GL_BGR , GL_UNSIGNED_INT_8_8_8_8_REV },
};
/* GLX_SWAP_COPY_OML is only supported because the Intel driver doesn't
* support pageflipping at all.
*/
static const GLenum back_buffer_modes[] = {
GLX_NONE, GLX_SWAP_UNDEFINED_OML, GLX_SWAP_COPY_OML
};
u_int8_t depth_bits_array[4] = { 0, 16, 24 };
u_int8_t stencil_bits_array[4] = { 0, 0, 8 };
depth_buffer_factor = 4;
back_buffer_factor = (have_back_buffer) ? 3 : 1;
num_modes = ((pixel_bits==16) ? 1 : 2) *
depth_buffer_factor * back_buffer_factor * 4;
modes = (*dri_interface->createContextModes)(num_modes,
sizeof(__GLcontextModes));
m = modes;
for (i=((pixel_bits==16)?0:1);i<((pixel_bits==16)?1:3);i++) {
if (!driFillInModes(&m, fb_format_array[i].format,
fb_format_array[i].type,
depth_bits_array,
stencil_bits_array,
depth_buffer_factor,
back_buffer_modes,
back_buffer_factor,
GLX_TRUE_COLOR)) {
fprintf( stderr, "[%s:%u] Error creating FBConfig!\n",
__func__, __LINE__ );
return NULL;
}
if (!driFillInModes(&m, fb_format_array[i].format,
fb_format_array[i].type,
depth_bits_array,
stencil_bits_array,
depth_buffer_factor,
back_buffer_modes,
back_buffer_factor,
GLX_DIRECT_COLOR)) {
fprintf( stderr, "[%s:%u] Error creating FBConfig!\n",
__func__, __LINE__ );
return NULL;
}
}
return modes;
}
PUBLIC void *
__driCreateNewScreen_20050727(__DRInativeDisplay *dpy, int scrn,
__DRIscreen *psc, const __GLcontextModes * modes,
const __DRIversion * ddx_version,
const __DRIversion * dri_version,
const __DRIversion * drm_version,
const __DRIframebuffer * frame_buffer,
void * pSAREA, int fd, int internal_api_version,
const __DRIinterfaceMethods * interface,
__GLcontextModes ** driver_modes)
{
__DRIscreenPrivate *psp;
static const __DRIversion ddx_expected = { 1, 2, 0 };
static const __DRIversion dri_expected = { 4, 0, 0 };
static const __DRIversion drm_expected =
{ 0, 0, NOUVEAU_DRM_HEADER_PATCHLEVEL };
struct nouveau_dri *nv_dri = NULL;
dri_interface = interface;
if (!driCheckDriDdxDrmVersions2("nouveau",
dri_version, &dri_expected,
ddx_version, &ddx_expected,
drm_version, &drm_expected)) {
return NULL;
}
if (drm_expected.patch != drm_version->patch) {
fprintf(stderr, "Incompatible DRM patch level.\n"
"Expected: %d\n" "Current : %d\n",
drm_expected.patch, drm_version->patch);
return NULL;
}
psp = __driUtilCreateNewScreen(dpy, scrn, psc, NULL,
ddx_version, dri_version, drm_version,
frame_buffer, pSAREA, fd,
internal_api_version,
&nouveau_api);
if (psp == NULL)
return NULL;
nv_dri = psp->pDevPriv;
*driver_modes = nouveau_fill_in_modes(nv_dri->bpp,
(nv_dri->bpp == 16) ? 16 : 24,
(nv_dri->bpp == 16) ? 0 : 8,
1);
driInitExtensions(NULL, common_extensions, GL_FALSE);
driInitExtensions(NULL, nv40_extensions, GL_FALSE);
return (void *)psp;
}
@@ -0,0 +1,17 @@
#ifndef __NOUVEAU_SCREEN_H__
#define __NOUVEAU_SCREEN_H__
#include "xmlconfig.h"
#include "nouveau_device.h"
struct nouveau_screen {
__DRIscreenPrivate *driScrnPriv;
driOptionCache option_cache;
struct nouveau_device *device;
uint32_t front_offset;
uint32_t front_pitch;
};
#endif
@@ -0,0 +1,98 @@
#include "context.h"
#include "pipe/p_context.h"
#include "state_tracker/st_public.h"
#include "state_tracker/st_cb_fbo.h"
#include "nouveau_context.h"
#include "nouveau_local.h"
#include "nouveau_screen.h"
#include "nouveau_swapbuffers.h"
void
nouveau_copy_buffer(__DRIdrawablePrivate *dPriv, struct pipe_surface *surf,
const drm_clip_rect_t *rect)
{
struct nouveau_context *nv = dPriv->driContextPriv->driverPrivate;
struct nouveau_screen *nv_screen = nv->nv_screen;
struct pipe_region *p_region = surf->region;
drm_clip_rect_t *pbox;
int nbox, i;
LOCK_HARDWARE(nv);
if (!dPriv->numClipRects) {
UNLOCK_HARDWARE(nv);
return;
}
pbox = dPriv->pClipRects;
nbox = dPriv->numClipRects;
BEGIN_RING(NvCtxSurf2D, 0x184, 2);
OUT_RELOCo(p_region->buffer, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
OUT_RING (nv->channel->vram->handle);
BEGIN_RING(NvCtxSurf2D, 0x300, 4);
OUT_RING ((p_region->cpp == 4) ? 6 : 4);
OUT_RING ((nv_screen->front_pitch << 16) |
(p_region->pitch * p_region->cpp));
OUT_RELOCl(p_region->buffer, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
OUT_RING (nv_screen->front_offset);
for (i = 0; i < nbox; i++, pbox++) {
int sx, sy, dx, dy, w, h;
sx = pbox->x1 - dPriv->x;
sy = pbox->y1 - dPriv->y;
dx = pbox->x1;
dy = pbox->y1;
w = pbox->x2 - pbox->x1;
h = pbox->y2 - pbox->y1;
BEGIN_RING(NvImageBlit, 0x300, 3);
OUT_RING ((sy << 16) | sx);
OUT_RING ((dy << 16) | dx);
OUT_RING (( h << 16) | w);
}
FIRE_RING();
UNLOCK_HARDWARE(nv);
if (nv->last_stamp != dPriv->lastStamp) {
struct nouveau_framebuffer *nvfb = dPriv->driverPrivate;
st_resize_framebuffer(nvfb->stfb, dPriv->w, dPriv->h);
nv->last_stamp = dPriv->lastStamp;
}
}
void
nouveau_copy_sub_buffer(__DRIdrawablePrivate *dPriv, int x, int y, int w, int h)
{
struct nouveau_framebuffer *nvfb = dPriv->driverPrivate;
struct pipe_surface *surf;
surf = st_get_framebuffer_surface(nvfb->stfb, ST_SURFACE_BACK_LEFT);
if (surf) {
drm_clip_rect_t rect;
rect.x1 = x;
rect.y1 = y;
rect.x2 = x + w;
rect.y2 = y + h;
st_notify_swapbuffers(nvfb->stfb);
nouveau_copy_buffer(dPriv, surf, &rect);
}
}
void
nouveau_swap_buffers(__DRIdrawablePrivate *dPriv)
{
struct nouveau_framebuffer *nvfb = dPriv->driverPrivate;
struct pipe_surface *surf;
surf = st_get_framebuffer_surface(nvfb->stfb, ST_SURFACE_BACK_LEFT);
if (surf) {
st_notify_swapbuffers(nvfb->stfb);
nouveau_copy_buffer(dPriv, surf, NULL);
}
}
@@ -0,0 +1,10 @@
#ifndef __NOUVEAU_SWAPBUFFERS_H__
#define __NOUVEAU_SWAPBUFFERS_H__
extern void nouveau_copy_buffer(__DRIdrawablePrivate *, struct pipe_surface *,
const drm_clip_rect_t *);
extern void nouveau_copy_sub_buffer(__DRIdrawablePrivate *,
int x, int y, int w, int h);
extern void nouveau_swap_buffers(__DRIdrawablePrivate *);
#endif
@@ -0,0 +1,90 @@
#include "nouveau_context.h"
#include "nouveau_winsys_pipe.h"
#include "pipe/nouveau/nouveau_winsys.h"
static int
nouveau_pipe_notifier_alloc(struct nouveau_winsys *nvws, int count,
struct nouveau_notifier **notify)
{
struct nouveau_context *nv = nvws->nv;
return nouveau_notifier_alloc(nv->channel, nv->next_handle++,
count, notify);
}
static int
nouveau_pipe_grobj_alloc(struct nouveau_winsys *nvws, int grclass,
struct nouveau_grobj **grobj)
{
struct nouveau_context *nv = nvws->nv;
return nouveau_grobj_alloc(nv->channel, nv->next_handle++,
grclass, grobj);
}
static uint32_t *
nouveau_pipe_dma_beginp(struct nouveau_grobj *grobj, int mthd, int size)
{
struct nouveau_channel_priv *chan = nouveau_channel(grobj->channel);
uint32_t *pushbuf;
BEGIN_RING_CH(&chan->base, grobj, mthd, size);
pushbuf = &chan->pushbuf[chan->dma.cur];
chan->dma.cur += size;
#ifdef NOUVEAU_DMA_DEBUG
chan->dma.push_free -= size;
#endif
return pushbuf;
}
static void
nouveau_pipe_dma_kickoff(struct nouveau_channel *userchan)
{
FIRE_RING_CH(userchan);
}
struct pipe_context *
nouveau_pipe_create(struct nouveau_context *nv)
{
struct nouveau_winsys *nvws = CALLOC_STRUCT(nouveau_winsys);
struct pipe_context *(*hw_create)(struct pipe_winsys *,
struct nouveau_winsys *,
unsigned);
if (!nvws)
return NULL;
switch (nv->chipset & 0xf0) {
case 0x40:
hw_create = nv40_create;
break;
default:
NOUVEAU_ERR("Unknown chipset NV%02x\n", (int)nv->chipset);
return NULL;
}
nvws->nv = nv;
nvws->channel = nv->channel;
nvws->begin_ring = nouveau_pipe_dma_beginp;
nvws->out_reloc = nouveau_bo_emit_reloc;
nvws->fire_ring = nouveau_pipe_dma_kickoff;
nvws->grobj_alloc = nouveau_pipe_grobj_alloc;
nvws->grobj_free = nouveau_grobj_free;
nvws->notifier_alloc = nouveau_pipe_notifier_alloc;
nvws->notifier_free = nouveau_notifier_free;
nvws->notifier_reset = nouveau_notifier_reset;
nvws->notifier_status = nouveau_notifier_status;
nvws->notifier_retval = nouveau_notifier_return_val;
nvws->notifier_wait = nouveau_notifier_wait_status;
nvws->region_copy = nv->region_copy;
nvws->region_fill = nv->region_fill;
nvws->region_data = nv->region_data;
return hw_create(nouveau_create_pipe_winsys(nv), nvws, nv->chipset);
}
@@ -0,0 +1,251 @@
#include "pipe/p_winsys.h"
#include "pipe/p_defines.h"
#include "nouveau_context.h"
#include "nouveau_device.h"
#include "nouveau_local.h"
#include "nouveau_screen.h"
#include "nouveau_swapbuffers.h"
#include "nouveau_winsys_pipe.h"
static void
nouveau_flush_frontbuffer(struct pipe_winsys *pws, struct pipe_surface *surf,
void *context_private)
{
struct nouveau_context *nv = context_private;
__DRIdrawablePrivate *dPriv = nv->dri_drawable;
nouveau_copy_buffer(dPriv, surf, NULL);
}
static void
nouveau_printf(struct pipe_winsys *pws, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
}
static const char *
nouveau_get_name(struct pipe_winsys *pws)
{
return "Nouveau/DRI";
}
static struct pipe_region *
nouveau_region_alloc(struct pipe_winsys *ws, unsigned cpp,
unsigned width, unsigned height, unsigned flags)
{
struct pipe_region *region;
region = calloc(sizeof(*region), 1);
region->cpp = cpp;
region->pitch = ((cpp * width + 63) & ~63) / cpp;
region->height = height;
region->refcount = 1;
region->buffer = ws->buffer_create(ws, 64);
ws->buffer_data(ws, region->buffer, region->pitch * cpp * height, NULL,
PIPE_BUFFER_USAGE_PIXEL);
return region;
}
static void
nouveau_region_release(struct pipe_winsys *pws, struct pipe_region **pregion)
{
struct pipe_region *region;
if (!pregion || !*pregion)
return;
region = *pregion;
*pregion = NULL;
assert(region->refcount > 0);
region->refcount--;
if (region->refcount == 0) {
assert(region->map_refcount == 0);
pws->buffer_reference(pws, &region->buffer, NULL);
free(region);
}
}
static struct pipe_surface *
nouveau_surface_alloc(struct pipe_winsys *pws, unsigned format)
{
struct pipe_surface *surf;
surf = CALLOC_STRUCT(pipe_surface);
if (!surf)
return NULL;
surf->format = format;
surf->refcount = 1;
surf->winsys = pws;
return surf;
}
static void
nouveau_surface_release(struct pipe_winsys *pws, struct pipe_surface **s)
{
struct pipe_surface *surf = *s; *s = NULL;
if (surf->refcount-- == 0) {
if (surf->region)
pws->region_release(pws, &surf->region);
free(surf);
}
}
static struct pipe_buffer_handle *
nouveau_pipe_bo_create(struct pipe_winsys *pws, unsigned alignment)
{
struct nouveau_pipe_winsys *nvpws = (struct nouveau_pipe_winsys *)pws;
struct nouveau_device *dev = nvpws->nv->nv_screen->device;
struct nouveau_bo *nvbo = NULL;
if (nouveau_bo_new(dev, NOUVEAU_BO_LOCAL, alignment, 0, &nvbo))
return NULL;
return (struct pipe_buffer_handle *)nvbo;
}
static struct pipe_buffer_handle *
nouveau_pipe_bo_user_create(struct pipe_winsys *pws, void *ptr, unsigned bytes)
{
struct nouveau_pipe_winsys *nvpws = (struct nouveau_pipe_winsys *)pws;
struct nouveau_device *dev = nvpws->nv->nv_screen->device;
struct nouveau_bo *nvbo = NULL;
if (nouveau_bo_user(dev, ptr, bytes, &nvbo))
return NULL;
return (struct pipe_buffer_handle *)nvbo;
}
static void *
nouveau_pipe_bo_map(struct pipe_winsys *pws, struct pipe_buffer_handle *bo,
unsigned flags)
{
struct nouveau_bo *nvbo = (struct nouveau_bo *)bo;
uint32_t map_flags = 0;
if (flags & PIPE_BUFFER_FLAG_READ)
map_flags |= NOUVEAU_BO_RD;
if (flags & PIPE_BUFFER_FLAG_WRITE)
map_flags |= NOUVEAU_BO_WR;
if (nouveau_bo_map(nvbo, map_flags))
return NULL;
return nvbo->map;
}
static void
nouveau_pipe_bo_unmap(struct pipe_winsys *pws, struct pipe_buffer_handle *bo)
{
struct nouveau_bo *nvbo = (struct nouveau_bo *)bo;
nouveau_bo_unmap(nvbo);
}
static void
nouveau_pipe_bo_reference(struct pipe_winsys *pws,
struct pipe_buffer_handle **ptr,
struct pipe_buffer_handle *bo)
{
struct nouveau_pipe_winsys *nvpws = (struct nouveau_pipe_winsys *)pws;
struct nouveau_context *nv = nvpws->nv;
struct nouveau_device *dev = nv->nv_screen->device;
if (*ptr) {
struct nouveau_bo *nvbo = (struct nouveau_bo *)*ptr;
FIRE_RING();
nouveau_bo_del(&nvbo);
*ptr = NULL;
}
if (bo) {
struct nouveau_bo *nvbo = (struct nouveau_bo *)bo, *new = NULL;
nouveau_bo_ref(dev, nvbo->handle, &new);
*ptr = bo;
}
}
static void
nouveau_pipe_bo_data(struct pipe_winsys *pws, struct pipe_buffer_handle *bo,
unsigned size, const void *data, unsigned usage)
{
struct nouveau_bo *nvbo = (struct nouveau_bo *)bo;
if (nvbo->size != size)
nouveau_bo_resize(nvbo, size);
if (data) {
if (nouveau_bo_map(nvbo, NOUVEAU_BO_WR))
return;
memcpy(nvbo->map, data, size);
nouveau_bo_unmap(nvbo);
}
}
static void
nouveau_pipe_bo_subdata(struct pipe_winsys *pws, struct pipe_buffer_handle *bo,
unsigned long offset, unsigned long size,
const void *data)
{
struct nouveau_bo *nvbo = (struct nouveau_bo *)bo;
if (nouveau_bo_map(nvbo, NOUVEAU_BO_WR))
return;
memcpy(nvbo->map + offset, data, size);
nouveau_bo_unmap(nvbo);
}
static void
nouveau_pipe_bo_get_subdata(struct pipe_winsys *pws,
struct pipe_buffer_handle *bo, unsigned long offset,
unsigned long size, void *data)
{
struct nouveau_bo *nvbo = (struct nouveau_bo *)bo;
if (nouveau_bo_map(nvbo, NOUVEAU_BO_RD))
return;
memcpy(data, nvbo->map + offset, size);
nouveau_bo_unmap(nvbo);
}
struct pipe_winsys *
nouveau_create_pipe_winsys(struct nouveau_context *nv)
{
struct nouveau_pipe_winsys *nvpws;
struct pipe_winsys *pws;
nvpws = CALLOC_STRUCT(nouveau_pipe_winsys);
if (!nvpws)
return NULL;
nvpws->nv = nv;
pws = &nvpws->pws;
pws->flush_frontbuffer = nouveau_flush_frontbuffer;
pws->printf = nouveau_printf;
pws->region_alloc = nouveau_region_alloc;
pws->region_release = nouveau_region_release;
pws->surface_alloc = nouveau_surface_alloc;
pws->surface_release = nouveau_surface_release;
pws->buffer_create = nouveau_pipe_bo_create;
pws->user_buffer_create = nouveau_pipe_bo_user_create;
pws->buffer_map = nouveau_pipe_bo_map;
pws->buffer_unmap = nouveau_pipe_bo_unmap;
pws->buffer_reference = nouveau_pipe_bo_reference;
pws->buffer_data = nouveau_pipe_bo_data;
pws->buffer_subdata = nouveau_pipe_bo_subdata;
pws->buffer_get_subdata= nouveau_pipe_bo_get_subdata;
pws->get_name = nouveau_get_name;
return &nvpws->pws;
}
@@ -0,0 +1,23 @@
#ifndef NOUVEAU_PIPE_WINSYS_H
#define NOUVEAU_PIPE_WINSYS_H
#include "pipe/p_context.h"
#include "pipe/p_winsys.h"
#include "nouveau_context.h"
struct nouveau_pipe_winsys {
struct pipe_winsys pws;
struct nouveau_context *nv;
};
extern struct pipe_winsys *
nouveau_create_pipe_winsys(struct nouveau_context *nv);
struct pipe_context *
nouveau_create_softpipe(struct nouveau_context *nv);
struct pipe_context *
nouveau_pipe_create(struct nouveau_context *nv);
#endif
@@ -0,0 +1,82 @@
/**************************************************************************
*
* Copyright 2006 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 <keithw-at-tungstengraphics-dot-com>
*/
#include "imports.h"
#include "pipe/softpipe/sp_winsys.h"
#include "pipe/p_defines.h"
#include "nouveau_context.h"
#include "nouveau_winsys_pipe.h"
struct nouveau_softpipe_winsys {
struct softpipe_winsys sws;
struct nouveau_context *nv;
};
/**
* Return list of surface formats supported by this driver.
*/
static boolean
nouveau_is_format_supported(struct softpipe_winsys *sws, uint format)
{
switch (format) {
case PIPE_FORMAT_U_A8_R8_G8_B8:
case PIPE_FORMAT_U_R5_G6_B5:
case PIPE_FORMAT_S8_Z24:
return TRUE;
default:
break;
};
return FALSE;
}
struct pipe_context *
nouveau_create_softpipe(struct nouveau_context *nv)
{
struct nouveau_softpipe_winsys *nvsws;
nvsws = CALLOC_STRUCT(nouveau_softpipe_winsys);
/* Fill in this struct with callbacks that softpipe will need to
* communicate with the window system, buffer manager, etc.
*/
nvsws->sws.is_format_supported = nouveau_is_format_supported;
nvsws->nv = nv;
/* Create the softpipe context:
*/
return softpipe_create(nouveau_create_pipe_winsys(nv), &nvsws->sws);
}
@@ -0,0 +1,163 @@
#include "pipe/p_context.h"
#include "nouveau_context.h"
static INLINE int
nv04_surface_format(int cpp)
{
switch (cpp) {
case 1: return 0x1;
case 2: return 0x4;
case 4: return 0xb;
default:
return -1;
}
}
static INLINE int
nv04_rect_format(int cpp)
{
switch (cpp) {
case 1: return 0x3;
case 2: return 0x1;
case 4: return 0x3;
default:
return -1;
}
}
static int
nv04_region_display(void)
{
NOUVEAU_ERR("unimplemented\n");
return 0;
}
static int
nv04_region_copy(struct nouveau_context *nv, struct pipe_region *dst,
unsigned dst_offset, unsigned dx, unsigned dy,
struct pipe_region *src, unsigned src_offset,
unsigned sx, unsigned sy, unsigned w, unsigned h)
{
int format;
if (src->cpp != dst->cpp)
return 1;
if ((format = nv04_surface_format(dst->cpp)) < 0) {
NOUVEAU_ERR("Bad cpp = %d\n", dst->cpp);
return 1;
}
BEGIN_RING(NvCtxSurf2D, 0x0184, 2);
OUT_RELOCo(src->buffer, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
OUT_RELOCo(dst->buffer, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
BEGIN_RING(NvCtxSurf2D, 0x0300, 4);
OUT_RING (format);
OUT_RING (((dst->pitch * dst->cpp) << 16) | (src->pitch * src->cpp));
OUT_RELOCl(src->buffer, src_offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
OUT_RELOCl(dst->buffer, dst_offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
BEGIN_RING(NvImageBlit, 0x0300, 3);
OUT_RING ((sy << 16) | sx);
OUT_RING ((dy << 16) | dx);
OUT_RING (( h << 16) | w);
return 0;
}
static int
nv04_region_fill(struct nouveau_context *nv,
struct pipe_region *dst, unsigned dst_offset,
unsigned dx, unsigned dy, unsigned w, unsigned h,
unsigned value)
{
int cs2d_format, gdirect_format;
if ((cs2d_format = nv04_surface_format(dst->cpp)) < 0) {
NOUVEAU_ERR("Bad cpp = %d\n", dst->cpp);
return 1;
}
if ((gdirect_format = nv04_rect_format(dst->cpp)) < 0) {
NOUVEAU_ERR("Bad cpp = %d\n", dst->cpp);
return 1;
}
BEGIN_RING(NvCtxSurf2D, 0x0184, 2);
OUT_RELOCo(dst->buffer, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
OUT_RELOCo(dst->buffer, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
BEGIN_RING(NvCtxSurf2D, 0x0300, 4);
OUT_RING (cs2d_format);
OUT_RING (((dst->pitch * dst->cpp) << 16) | (dst->pitch * dst->cpp));
OUT_RELOCl(dst->buffer, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
OUT_RELOCl(dst->buffer, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
BEGIN_RING(NvGdiRect, 0x0300, 1);
OUT_RING (gdirect_format);
BEGIN_RING(NvGdiRect, 0x03fc, 1);
OUT_RING (value);
BEGIN_RING(NvGdiRect, 0x0400, 2);
OUT_RING ((dx << 16) | dy);
OUT_RING (( w << 16) | h);
return 0;
}
static int
nv04_region_data(struct nouveau_context *nv, struct pipe_region *dst,
unsigned dst_offset, unsigned dx, unsigned dy,
const void *src, unsigned src_pitch,
unsigned sx, unsigned sy, unsigned w, unsigned h)
{
NOUVEAU_ERR("unimplemented!!\n");
return 0;
}
int
nouveau_region_init_nv04(struct nouveau_context *nv)
{
int ret;
if ((ret = nouveau_grobj_alloc(nv->channel, nv->next_handle++, 0x62,
&nv->NvCtxSurf2D))) {
NOUVEAU_ERR("Error creating 2D surface object: %d\n", ret);
return 1;
}
BEGIN_RING(NvCtxSurf2D, 0x0184, 2);
OUT_RING (nv->channel->vram->handle);
OUT_RING (nv->channel->vram->handle);
if ((ret = nouveau_grobj_alloc(nv->channel, nv->next_handle++, 0x9f,
&nv->NvImageBlit))) {
NOUVEAU_ERR("Error creating blit object: %d\n", ret);
return 1;
}
BEGIN_RING(NvImageBlit, 0x0180, 1);
OUT_RING (nv->sync_notifier->handle);
BEGIN_RING(NvImageBlit, 0x019c, 1);
OUT_RING (nv->NvCtxSurf2D->handle);
BEGIN_RING(NvImageBlit, 0x02fc, 1);
OUT_RING (3);
if ((ret = nouveau_grobj_alloc(nv->channel, nv->next_handle++, 0x4a,
&nv->NvGdiRect))) {
NOUVEAU_ERR("Error creating rect object: %d\n", ret);
return 1;
}
BEGIN_RING(NvGdiRect, 0x0180, 1);
OUT_RING (nv->sync_notifier->handle);
BEGIN_RING(NvGdiRect, 0x0198, 1);
OUT_RING (nv->NvCtxSurf2D->handle);
BEGIN_RING(NvGdiRect, 0x02fc, 1);
OUT_RING (3);
BEGIN_RING(NvGdiRect, 0x0304, 1);
OUT_RING (2);
nv->region_display = nv04_region_display;
nv->region_copy = nv04_region_copy;
nv->region_fill = nv04_region_fill;
nv->region_data = nv04_region_data;
return 0;
}
@@ -0,0 +1,51 @@
#include "pipe/p_context.h"
#include "nouveau_context.h"
static int
nv50_region_display(void)
{
NOUVEAU_ERR("unimplemented\n");
return 0;
}
static int
nv50_region_copy(struct nouveau_context *nv, struct pipe_region *dst,
unsigned dst_offset, unsigned dx, unsigned dy,
struct pipe_region *src, unsigned src_offset,
unsigned sx, unsigned sy, unsigned w, unsigned h)
{
NOUVEAU_ERR("unimplemented!!\n");
return 0;
}
static int
nv50_region_fill(struct nouveau_context *nv,
struct pipe_region *dst, unsigned dst_offset,
unsigned dx, unsigned dy, unsigned w, unsigned h,
unsigned value)
{
NOUVEAU_ERR("unimplemented!!\n");
return 0;
}
static int
nv50_region_data(struct nouveau_context *nv, struct pipe_region *dst,
unsigned dst_offset, unsigned dx, unsigned dy,
const void *src, unsigned src_pitch,
unsigned sx, unsigned sy, unsigned w, unsigned h)
{
NOUVEAU_ERR("unimplemented!!\n");
return 0;
}
int
nouveau_region_init_nv50(struct nouveau_context *nv)
{
nv->region_display = nv50_region_display;
nv->region_copy = nv50_region_copy;
nv->region_fill = nv50_region_fill;
nv->region_data = nv50_region_data;
return 0;
}
+2 -1
View File
@@ -2,6 +2,7 @@ default:
cd softpipe ; make
cd i915simple ; make
cd failover ; make
cd nv40; make
clean:
rm -f `find . -name \*.[oa]`
rm -f `find . -name \*.[oa]`
+50
View File
@@ -0,0 +1,50 @@
/*
* Copyright 2007 Nouveau Project
*
* 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, sublicense,
* 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 above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* 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 NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS 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.
*/
#ifndef __NOUVEAU_BO_H__
#define __NOUVEAU_BO_H__
/* Relocation/Buffer type flags */
#define NOUVEAU_BO_VRAM (1 << 0)
#define NOUVEAU_BO_GART (1 << 1)
#define NOUVEAU_BO_RD (1 << 2)
#define NOUVEAU_BO_WR (1 << 3)
#define NOUVEAU_BO_RDWR (NOUVEAU_BO_RD | NOUVEAU_BO_WR)
#define NOUVEAU_BO_MAP (1 << 4)
#define NOUVEAU_BO_PIN (1 << 5)
#define NOUVEAU_BO_LOW (1 << 6)
#define NOUVEAU_BO_HIGH (1 << 7)
#define NOUVEAU_BO_OR (1 << 8)
#define NOUVEAU_BO_LOCAL (1 << 9)
struct nouveau_bo {
struct nouveau_device *device;
uint64_t handle;
uint64_t size;
void *map;
uint32_t flags;
uint64_t offset;
};
#endif
+37
View File
@@ -0,0 +1,37 @@
/*
* Copyright 2007 Nouveau Project
*
* 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, sublicense,
* 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 above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* 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 NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS 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.
*/
#ifndef __NOUVEAU_CHANNEL_H__
#define __NOUVEAU_CHANNEL_H__
struct nouveau_channel {
struct nouveau_device *device;
int id;
struct nouveau_grobj *vram;
struct nouveau_grobj *gart;
void *user_private;
void (*hang_notify)(struct nouveau_channel *);
};
#endif
File diff suppressed because it is too large Load Diff
+41
View File
@@ -0,0 +1,41 @@
/*
* Copyright 2007 Nouveau Project
*
* 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, sublicense,
* 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 above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* 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 NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS 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.
*/
#ifndef __NOUVEAU_GROBJ_H__
#define __NOUVEAU_GROBJ_H__
#include "nouveau_channel.h"
struct nouveau_grobj {
struct nouveau_channel *channel;
int grclass;
uint32_t handle;
enum {
NOUVEAU_GROBJ_UNBOUND = 0,
NOUVEAU_GROBJ_BOUND = 1,
NOUVEAU_GROBJ_EXPLICIT_BIND = 2,
} bound;
int subc;
};
#endif
+43
View File
@@ -0,0 +1,43 @@
/*
* Copyright 2007 Nouveau Project
*
* 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, sublicense,
* 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 above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* 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 NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS 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.
*/
#ifndef __NOUVEAU_NOTIFIER_H__
#define __NOUVEAU_NOTIFIER_H__
#define NV_NOTIFIER_SIZE 32
#define NV_NOTIFY_TIME_0 0x00000000
#define NV_NOTIFY_TIME_1 0x00000004
#define NV_NOTIFY_RETURN_VALUE 0x00000008
#define NV_NOTIFY_STATE 0x0000000C
#define NV_NOTIFY_STATE_STATUS_MASK 0xFF000000
#define NV_NOTIFY_STATE_STATUS_SHIFT 24
#define NV_NOTIFY_STATE_STATUS_COMPLETED 0x00
#define NV_NOTIFY_STATE_STATUS_IN_PROCESS 0x01
#define NV_NOTIFY_STATE_ERROR_CODE_MASK 0x0000FFFF
#define NV_NOTIFY_STATE_ERROR_CODE_SHIFT 0
struct nouveau_notifier {
struct nouveau_channel *channel;
uint32_t handle;
};
#endif
+53
View File
@@ -0,0 +1,53 @@
#ifndef NOUVEAU_WINSYS_H
#define NOUVEAU_WINSYS_H
#include <stdint.h>
#include "pipe/p_winsys.h"
#include "pipe/nouveau/nouveau_bo.h"
#include "pipe/nouveau/nouveau_channel.h"
#include "pipe/nouveau/nouveau_class.h"
#include "pipe/nouveau/nouveau_grobj.h"
#include "pipe/nouveau/nouveau_notifier.h"
struct nouveau_winsys {
struct nouveau_context *nv;
struct nouveau_channel *channel;
/*XXX: this is crappy, and bound to be slow.. however, it's nice and
* simple, it'll do for the moment*/
uint32_t *(*begin_ring)(struct nouveau_grobj *, int mthd, int size);
void (*out_reloc)(struct nouveau_channel *, void *ptr,
struct nouveau_bo *, uint32_t data,
uint32_t flags, uint32_t vor, uint32_t tor);
void (*fire_ring)(struct nouveau_channel *);
int (*grobj_alloc)(struct nouveau_winsys *, int grclass,
struct nouveau_grobj **);
void (*grobj_free)(struct nouveau_grobj **);
int (*notifier_alloc)(struct nouveau_winsys *, int count,
struct nouveau_notifier **);
void (*notifier_free)(struct nouveau_notifier **);
void (*notifier_reset)(struct nouveau_notifier *, int id);
uint32_t (*notifier_status)(struct nouveau_notifier *, int id);
uint32_t (*notifier_retval)(struct nouveau_notifier *, int id);
int (*notifier_wait)(struct nouveau_notifier *, int id,
int status, int timeout);
int (*region_copy)(struct nouveau_context *, struct pipe_region *,
unsigned, unsigned, unsigned, struct pipe_region *,
unsigned, unsigned, unsigned, unsigned, unsigned);
int (*region_fill)(struct nouveau_context *, struct pipe_region *,
unsigned, unsigned, unsigned, unsigned, unsigned,
unsigned);
int (*region_data)(struct nouveau_context *, struct pipe_region *,
unsigned, unsigned, unsigned, const void *,
unsigned, unsigned, unsigned, unsigned, unsigned);
};
extern struct pipe_context *
nv40_create(struct pipe_winsys *, struct nouveau_winsys *, unsigned chipset);
#endif
+30
View File
@@ -0,0 +1,30 @@
TOP = ../../../..
include $(TOP)/configs/current
LIBNAME = nv40
DRIVER_SOURCES = \
nv40_clear.c \
nv40_context.c \
nv40_draw.c \
nv40_fragprog.c \
nv40_miptree.c \
nv40_query.c \
nv40_region.c \
nv40_state.c \
nv40_state_emit.c \
nv40_state_tex.c \
nv40_surface.c \
nv40_vbo.c \
nv40_vertprog.c
C_SOURCES = \
$(COMMON_SOURCES) \
$(DRIVER_SOURCES)
ASM_SOURCES =
include ../Makefile.template
symlinks:
+21
View File
@@ -0,0 +1,21 @@
#include "pipe/p_context.h"
#include "pipe/p_defines.h"
#include "pipe/p_state.h"
#include "nv40_context.h"
#include "nv40_dma.h"
void
nv40_clear(struct pipe_context *pipe, struct pipe_surface *ps,
unsigned clearValue)
{
/*XXX: We're actually Z24_S8... */
if (ps->format == PIPE_FORMAT_S8_Z24) {
clearValue = (((clearValue & 0xff000000) >> 24) |
((clearValue & 0x00ffffff) << 8));
}
pipe->region_fill(pipe, ps->region, 0, 0, 0, ps->width, ps->height,
clearValue);
}
+277
View File
@@ -0,0 +1,277 @@
#include "pipe/draw/draw_context.h"
#include "pipe/p_defines.h"
#include "pipe/p_winsys.h"
#include "pipe/p_util.h"
#include "nv40_context.h"
#include "nv40_dma.h"
static boolean
nv40_is_format_supported(struct pipe_context *pipe, uint format)
{
switch (format) {
case PIPE_FORMAT_U_A8_R8_G8_B8:
case PIPE_FORMAT_U_R5_G6_B5:
case PIPE_FORMAT_S8_Z24:
return TRUE;
default:
break;
};
return FALSE;
}
static const char *
nv40_get_name(struct pipe_context *pipe)
{
struct nv40_context *nv40 = (struct nv40_context *)pipe;
static char buffer[128];
snprintf(buffer, sizeof(buffer), "NV%02X", nv40->chipset);
return buffer;
}
static const char *
nv40_get_vendor(struct pipe_context *pipe)
{
return "nouveau";
}
static int
nv40_get_param(struct pipe_context *pipe, int param)
{
switch (param) {
case PIPE_CAP_MAX_TEXTURE_IMAGE_UNITS:
return 16;
case PIPE_CAP_NPOT_TEXTURES:
return 1;
case PIPE_CAP_TWO_SIDED_STENCIL:
return 1;
case PIPE_CAP_GLSL:
return 0;
case PIPE_CAP_S3TC:
return 0;
case PIPE_CAP_ANISOTROPIC_FILTER:
return 0;
case PIPE_CAP_POINT_SPRITE:
return 0;
case PIPE_CAP_MAX_RENDER_TARGETS:
return 4;
case PIPE_CAP_OCCLUSION_QUERY:
return 1;
case PIPE_CAP_TEXTURE_SHADOW_MAP:
return 0;
case PIPE_CAP_MAX_TEXTURE_2D_LEVELS:
return 13;
case PIPE_CAP_MAX_TEXTURE_3D_LEVELS:
return 10;
case PIPE_CAP_MAX_TEXTURE_CUBE_LEVELS:
return 13;
default:
NOUVEAU_ERR("Unknown PIPE_CAP %d\n", param);
return 0;
}
}
static float
nv40_get_paramf(struct pipe_context *pipe, int param)
{
switch (param) {
case PIPE_CAP_MAX_LINE_WIDTH:
case PIPE_CAP_MAX_LINE_WIDTH_AA:
case PIPE_CAP_MAX_POINT_WIDTH:
case PIPE_CAP_MAX_POINT_WIDTH_AA:
case PIPE_CAP_MAX_TEXTURE_ANISOTROPY:
case PIPE_CAP_MAX_TEXTURE_LOD_BIAS:
default:
NOUVEAU_ERR("Unknown PIPE_CAP %d\n", param);
return 0.0;
}
}
static void
nv40_flush(struct pipe_context *pipe, unsigned flags)
{
struct nv40_context *nv40 = (struct nv40_context *)pipe;
struct nouveau_winsys *nvws = nv40->nvws;
if (flags & PIPE_FLUSH_TEXTURE_CACHE) {
BEGIN_RING(curie, 0x1fd8, 1);
OUT_RING (2);
BEGIN_RING(curie, 0x1fd8, 1);
OUT_RING (1);
}
if (flags & PIPE_FLUSH_WAIT) {
nvws->notifier_reset(nv40->sync, 0);
BEGIN_RING(curie, 0x104, 1);
OUT_RING (0);
BEGIN_RING(curie, 0x100, 1);
OUT_RING (0);
}
FIRE_RING();
if (flags & PIPE_FLUSH_WAIT)
nvws->notifier_wait(nv40->sync, 0, 0, 2000);
}
static void
nv40_destroy(struct pipe_context *pipe)
{
struct nv40_context *nv40 = (struct nv40_context *)pipe;
draw_destroy(nv40->draw);
free(nv40);
}
static boolean
nv40_init_hwctx(struct nv40_context *nv40, int curie_class)
{
struct nouveau_winsys *nvws = nv40->nvws;
int ret;
if ((ret = nvws->notifier_alloc(nvws, nv40->num_query_objects,
&nv40->query))) {
NOUVEAU_ERR("Error creating query notifier objects: %d\n", ret);
return FALSE;
}
if ((ret = nvws->grobj_alloc(nvws, curie_class,
&nv40->curie))) {
NOUVEAU_ERR("Error creating 3D object: %d\n", ret);
return FALSE;
}
BEGIN_RING(curie, NV40TCL_DMA_NOTIFY, 1);
OUT_RING (nv40->sync->handle);
BEGIN_RING(curie, NV40TCL_DMA_TEXTURE0, 2);
OUT_RING (nvws->channel->vram->handle);
OUT_RING (nvws->channel->gart->handle);
BEGIN_RING(curie, NV40TCL_DMA_COLOR1, 1);
OUT_RING (nvws->channel->vram->handle);
BEGIN_RING(curie, NV40TCL_DMA_COLOR0, 2);
OUT_RING (nvws->channel->vram->handle);
OUT_RING (nvws->channel->vram->handle);
BEGIN_RING(curie, NV40TCL_DMA_VTXBUF0, 2);
OUT_RING (nvws->channel->vram->handle);
OUT_RING (nvws->channel->gart->handle);
BEGIN_RING(curie, NV40TCL_DMA_FENCE, 2);
OUT_RING (0);
OUT_RING (nv40->query->handle);
BEGIN_RING(curie, NV40TCL_DMA_UNK01AC, 2);
OUT_RING (nvws->channel->vram->handle);
OUT_RING (nvws->channel->vram->handle);
BEGIN_RING(curie, NV40TCL_DMA_COLOR2, 2);
OUT_RING (nvws->channel->vram->handle);
OUT_RING (nvws->channel->vram->handle);
BEGIN_RING(curie, 0x1ea4, 3);
OUT_RING (0x00000010);
OUT_RING (0x01000100);
OUT_RING (0xff800006);
/* vtxprog output routing */
BEGIN_RING(curie, 0x1fc4, 1);
OUT_RING (0x06144321);
BEGIN_RING(curie, 0x1fc8, 2);
OUT_RING (0xedcba987);
OUT_RING (0x00000021);
BEGIN_RING(curie, 0x1fd0, 1);
OUT_RING (0x00171615);
BEGIN_RING(curie, 0x1fd4, 1);
OUT_RING (0x001b1a19);
BEGIN_RING(curie, 0x1ef8, 1);
OUT_RING (0x0020ffff);
BEGIN_RING(curie, 0x1d64, 1);
OUT_RING (0x00d30000);
BEGIN_RING(curie, 0x1e94, 1);
OUT_RING (0x00000001);
FIRE_RING ();
return TRUE;
}
#define GRCLASS4097_CHIPSETS 0x00000baf
#define GRCLASS4497_CHIPSETS 0x00005450
struct pipe_context *
nv40_create(struct pipe_winsys *pipe_winsys, struct nouveau_winsys *nvws,
unsigned chipset)
{
struct nv40_context *nv40;
int curie_class, ret;
if ((chipset & 0xf0) != 0x40) {
NOUVEAU_ERR("Not a NV4X chipset\n");
return NULL;
}
if (GRCLASS4097_CHIPSETS & (1 << (chipset & 0x0f))) {
curie_class = 0x4097;
} else
if (GRCLASS4497_CHIPSETS & (1 << (chipset & 0x0f))) {
curie_class = 0x4497;
} else {
NOUVEAU_ERR("Unknown NV4X chipset: NV%02x\n", chipset);
return NULL;
}
nv40 = CALLOC_STRUCT(nv40_context);
if (!nv40)
return NULL;
nv40->chipset = chipset;
nv40->nvws = nvws;
if ((ret = nvws->notifier_alloc(nvws, 1, &nv40->sync))) {
NOUVEAU_ERR("Error creating notifier object: %d\n", ret);
free(nv40);
return NULL;
}
nv40->num_query_objects = 32;
nv40->query_objects = calloc(nv40->num_query_objects,
sizeof(struct pipe_query_object *));
if (!nv40->query_objects) {
free(nv40);
return NULL;
}
if (!nv40_init_hwctx(nv40, curie_class)) {
free(nv40);
return NULL;
}
nv40->pipe.winsys = pipe_winsys;
nv40->pipe.destroy = nv40_destroy;
nv40->pipe.is_format_supported = nv40_is_format_supported;
nv40->pipe.get_name = nv40_get_name;
nv40->pipe.get_vendor = nv40_get_vendor;
nv40->pipe.get_param = nv40_get_param;
nv40->pipe.get_paramf = nv40_get_paramf;
nv40->pipe.draw_arrays = nv40_draw_arrays;
nv40->pipe.draw_elements = nv40_draw_elements;
nv40->pipe.clear = nv40_clear;
nv40->pipe.begin_query = nv40_query_begin;
nv40->pipe.end_query = nv40_query_end;
nv40->pipe.wait_query = nv40_query_wait;
nv40->pipe.mipmap_tree_layout = nv40_miptree_layout;
nv40->pipe.flush = nv40_flush;
nv40_init_region_functions(nv40);
nv40_init_surface_functions(nv40);
nv40_init_state_functions(nv40);
nv40->draw = draw_create();
assert(nv40->draw);
draw_set_rasterize_stage(nv40->draw, nv40_draw_render_stage(nv40));
return &nv40->pipe;
}
+111
View File
@@ -0,0 +1,111 @@
#ifndef __NV40_CONTEXT_H__
#define __NV40_CONTEXT_H__
#include "pipe/p_context.h"
#include "pipe/p_defines.h"
#include "pipe/p_state.h"
#include "pipe/draw/draw_vertex.h"
#include "pipe/nouveau/nouveau_winsys.h"
#include "nv40_state.h"
#define NOUVEAU_ERR(fmt, args...) \
fprintf(stderr, "%s:%d - "fmt, __func__, __LINE__, ##args);
#define NOUVEAU_MSG(fmt, args...) \
fprintf(stderr, "nouveau: "fmt, ##args);
#define NV40_NEW_TEXTURE (1 << 0)
#define NV40_NEW_VERTPROG (1 << 1)
#define NV40_NEW_FRAGPROG (1 << 2)
#define NV40_NEW_ARRAYS (1 << 3)
struct nv40_context {
struct pipe_context pipe;
struct nouveau_winsys *nvws;
struct draw_context *draw;
int chipset;
struct nouveau_grobj *curie;
struct nouveau_notifier *sync;
uint32_t *pushbuf;
/* query objects */
struct nouveau_notifier *query;
struct pipe_query_object **query_objects;
uint num_query_objects;
uint32_t dirty;
struct nv40_sampler_state *tex_sampler[PIPE_MAX_SAMPLERS];
struct pipe_mipmap_tree *tex_miptree[PIPE_MAX_SAMPLERS];
uint32_t tex_dirty;
struct {
struct nv40_vertex_program *vp;
struct nv40_vertex_program *active_vp;
struct pipe_buffer_handle *constant_buf;
} vertprog;
struct {
struct nv40_fragment_program *fp;
struct nv40_fragment_program *active_fp;
struct pipe_buffer_handle *constant_buf;
} fragprog;
struct pipe_vertex_buffer vtxbuf[PIPE_ATTRIB_MAX];
struct pipe_vertex_element vtxelt[PIPE_ATTRIB_MAX];
};
extern void nv40_init_region_functions(struct nv40_context *nv40);
extern void nv40_init_surface_functions(struct nv40_context *nv40);
extern void nv40_init_state_functions(struct nv40_context *nv40);
/* nv40_draw.c */
extern struct draw_stage *nv40_draw_render_stage(struct nv40_context *nv40);
/* nv40_miptree.c */
extern boolean nv40_miptree_layout(struct pipe_context *,
struct pipe_mipmap_tree *);
/* nv40_vertprog.c */
extern void nv40_vertprog_translate(struct nv40_context *,
struct nv40_vertex_program *);
extern void nv40_vertprog_bind(struct nv40_context *,
struct nv40_vertex_program *);
/* nv40_fragprog.c */
extern void nv40_fragprog_translate(struct nv40_context *,
struct nv40_fragment_program *);
extern void nv40_fragprog_bind(struct nv40_context *,
struct nv40_fragment_program *);
/* nv40_state.c and friends */
extern void nv40_emit_hw_state(struct nv40_context *nv40);
extern void nv40_state_tex_update(struct nv40_context *nv40);
/* nv40_vbo.c */
extern boolean nv40_draw_arrays(struct pipe_context *, unsigned mode,
unsigned start, unsigned count);
extern boolean nv40_draw_elements(struct pipe_context *pipe,
struct pipe_buffer_handle *indexBuffer,
unsigned indexSize,
unsigned mode, unsigned start,
unsigned count);
extern void nv40_vbo_arrays_update(struct nv40_context *nv40);
/* nv40_clear.c */
extern void nv40_clear(struct pipe_context *pipe, struct pipe_surface *ps,
unsigned clearValue);
/* nv40_query.c */
extern void nv40_query_begin(struct pipe_context *, struct pipe_query_object *);
extern void nv40_query_end(struct pipe_context *, struct pipe_query_object *);
extern void nv40_query_wait(struct pipe_context *, struct pipe_query_object *);
#endif
+62
View File
@@ -0,0 +1,62 @@
#ifndef __NV40_DMA_H__
#define __NV40_DMA_H__
#include "pipe/nouveau/nouveau_winsys.h"
#define BEGIN_RING(obj,mthd,size) do { \
nv40->pushbuf = nv40->nvws->begin_ring(nv40->obj, (mthd), (size)); \
} while(0)
#define BEGIN_RING_NI(obj,mthd,size) do { \
BEGIN_RING(obj, (mthd) | 0x40000000, (size)); \
} while(0)
#define OUT_RING(data) do { \
(*nv40->pushbuf++) = (data); \
} while(0)
#define OUT_RINGp(src,size) do { \
memcpy(nv40->pushbuf, (src), (size) * 4); \
nv40->pushbuf += (size); \
} while(0)
#define OUT_RINGf(data) do { \
union { float v; uint32_t u; } c; \
c.v = (data); \
OUT_RING(c.u); \
} while(0)
#define FIRE_RING() do { \
nv40->nvws->fire_ring(nv40->nvws->channel); \
} while(0)
#define OUT_RELOC(bo,data,flags,vor,tor) do { \
nv40->nvws->out_reloc(nv40->nvws->channel, nv40->pushbuf, \
(struct nouveau_bo *)(bo), \
(data), (flags), (vor), (tor)); \
OUT_RING(0); \
} while(0)
/* Raw data + flags depending on FB/TT buffer */
#define OUT_RELOCd(bo,data,flags,vor,tor) do { \
OUT_RELOC((bo), (data), (flags) | NOUVEAU_BO_OR, (vor), (tor)); \
} while(0)
/* FB/TT object handle */
#define OUT_RELOCo(bo,flags) do { \
OUT_RELOC((bo), 0, (flags) | NOUVEAU_BO_OR, \
nv40->nvws->channel->vram->handle, \
nv40->nvws->channel->gart->handle); \
} while(0)
/* Low 32-bits of offset */
#define OUT_RELOCl(bo,delta,flags) do { \
OUT_RELOC((bo), (delta), (flags) | NOUVEAU_BO_LOW, 0, 0); \
} while(0)
/* High 32-bits of offset */
#define OUT_RELOCh(bo,delta,flags) do { \
OUT_RELOC((bo), (delta), (flags) | NOUVEAU_BO_HIGH, 0, 0); \
} while(0)
#endif
+63
View File
@@ -0,0 +1,63 @@
#include "pipe/draw/draw_private.h"
#include "pipe/p_util.h"
#include "nv40_context.h"
struct nv40_draw_stage {
struct draw_stage draw;
struct nv40_context *nv40;
};
static void
nv40_draw_begin(struct draw_stage *draw)
{
NOUVEAU_ERR("\n");
}
static void
nv40_draw_end(struct draw_stage *draw)
{
NOUVEAU_ERR("\n");
}
static void
nv40_draw_point(struct draw_stage *draw, struct prim_header *prim)
{
NOUVEAU_ERR("\n");
}
static void
nv40_draw_line(struct draw_stage *draw, struct prim_header *prim)
{
NOUVEAU_ERR("\n");
}
static void
nv40_draw_tri(struct draw_stage *draw, struct prim_header *prim)
{
NOUVEAU_ERR("\n");
}
static void
nv40_draw_reset_stipple_counter(struct draw_stage *draw)
{
NOUVEAU_ERR("\n");
}
struct draw_stage *
nv40_draw_render_stage(struct nv40_context *nv40)
{
struct nv40_draw_stage *nv40draw = CALLOC_STRUCT(nv40_draw_stage);
nv40draw->nv40 = nv40;
nv40draw->draw.draw = nv40->draw;
nv40draw->draw.begin = nv40_draw_begin;
nv40draw->draw.point = nv40_draw_point;
nv40draw->draw.line = nv40_draw_line;
nv40draw->draw.tri = nv40_draw_tri;
nv40draw->draw.end = nv40_draw_end;
nv40draw->draw.reset_stipple_counter = nv40_draw_reset_stipple_counter;
return &nv40draw->draw;
}
+642
View File
@@ -0,0 +1,642 @@
#include "pipe/p_context.h"
#include "pipe/p_defines.h"
#include "pipe/p_state.h"
#include "pipe/tgsi/exec/tgsi_token.h"
#include "pipe/tgsi/exec/tgsi_parse.h"
#include "nv40_context.h"
#include "nv40_dma.h"
#define SWZ_X 0
#define SWZ_Y 1
#define SWZ_Z 2
#define SWZ_W 3
#define MASK_X 1
#define MASK_Y 2
#define MASK_Z 4
#define MASK_W 8
#define MASK_ALL (MASK_X|MASK_Y|MASK_Z|MASK_W)
#define DEF_SCALE NV40_FP_OP_DST_SCALE_1X
#define DEF_CTEST NV40_FP_OP_COND_TR
#include "nv40_shader.h"
#define swz(s,x,y,z,w) nv40_sr_swz((s), SWZ_##x, SWZ_##y, SWZ_##z, SWZ_##w)
#define neg(s) nv40_sr_neg((s))
#define abs(s) nv40_sr_abs((s))
#define scale(s,v) nv40_sr_scale((s), NV40_FP_OP_DST_SCALE_##v)
static uint32_t
passthrough_fp_data[] = {
0x01403e81, 0x1c9dc801, 0x0001c800, 0x3fe1c800
};
static struct nv40_fragment_program
passthrough_fp = {
.pipe = NULL,
.translated = TRUE,
.insn = passthrough_fp_data,
.insn_len = sizeof(passthrough_fp_data) / sizeof(uint32_t),
.buffer = NULL,
.uses_kil = 0,
.num_regs = 2,
};
struct nv40_fpc {
struct nv40_fragment_program *fp;
uint attrib_map[PIPE_MAX_SHADER_INPUTS];
int high_temp;
int temp_temp_count;
uint depth_id;
uint colour_id;
boolean inst_has_const;
int inst_const_id;
};
static INLINE struct nv40_sreg
nv40_sr_temp(struct nv40_fpc *fpc)
{
int idx;
idx = fpc->temp_temp_count++;
idx += fpc->high_temp + 1;
return nv40_sr(0, NV40_FP_REG_TYPE_TEMP, idx);
}
#define arith(cc,s,o,d,m,s0,s1,s2) \
nv40_fp_arith((cc), (s), NV40_FP_OP_OPCODE_##o, \
(d), (m), (s0), (s1), (s2))
#define tex(cc,s,o,u,d,m,s0,s1,s2) \
nv40_fp_tex((cc), (s), NV40_FP_OP_OPCODE_##o, (u), \
(d), (m), (s0), none, none)
#define temp(fpc) nv40_sr_temp((fpc))
static void
emit_src(struct nv40_fpc *fpc, uint32_t *hw, int pos, struct nv40_sreg src)
{
uint32_t sr = 0;
sr |= (src.type << NV40_FP_REG_TYPE_SHIFT);
if (src.type == NV40_FP_REG_TYPE_INPUT) {
hw[0] |= (src.index << NV40_FP_OP_INPUT_SRC_SHIFT);
} else
if (src.type == NV40_FP_REG_TYPE_CONST) {
fpc->inst_has_const = TRUE;
} else
if (src.type == NV40_FP_REG_TYPE_TEMP) {
sr |= (src.index << NV40_FP_REG_SRC_SHIFT);
}
if (src.negate)
sr |= NV40_FP_REG_NEGATE;
if (src.abs)
hw[1] |= (1 << (29 + pos));
sr |= ((src.swz[0] << NV40_FP_REG_SWZ_X_SHIFT) |
(src.swz[1] << NV40_FP_REG_SWZ_Y_SHIFT) |
(src.swz[2] << NV40_FP_REG_SWZ_Z_SHIFT) |
(src.swz[3] << NV40_FP_REG_SWZ_W_SHIFT));
hw[pos + 1] |= sr;
}
static void
emit_dst(struct nv40_fpc *fpc, uint32_t *hw, struct nv40_sreg dst)
{
struct nv40_fragment_program *fp = fpc->fp;
if (dst.output) {
if (dst.index == 1) {
fp->writes_depth = 1;
} else {
hw[0] |= NV40_FP_OP_UNK0_7;
}
} else {
if (fp->num_regs < (dst.index + 1))
fp->num_regs = dst.index + 1;
}
hw[0] |= (dst.index << NV40_FP_OP_OUT_REG_SHIFT);
}
static void
nv40_fp_arith(struct nv40_fpc *fpc, int sat, int op,
struct nv40_sreg dst, int mask,
struct nv40_sreg s0, struct nv40_sreg s1, struct nv40_sreg s2)
{
struct nv40_fragment_program *fp = fpc->fp;
uint32_t *hw = &fp->insn[fp->insn_len];
fpc->inst_has_const = FALSE;
if (op == NV40_FP_OP_OPCODE_KIL)
fp->uses_kil = TRUE;
hw[0] |= (op << NV40_FP_OP_OPCODE_SHIFT);
hw[0] |= (mask << NV40_FP_OP_OUTMASK_SHIFT);
hw[2] |= (dst.dst_scale << NV40_FP_OP_DST_SCALE_SHIFT);
if (sat)
hw[0] |= NV40_FP_OP_OUT_SAT;
if (dst.cc_update)
hw[0] |= NV40_FP_OP_COND_WRITE_ENABLE;
hw[1] |= (dst.cc_test << NV40_FP_OP_COND_SHIFT);
hw[1] |= ((dst.cc_swz[0] << NV40_FP_OP_COND_SWZ_X_SHIFT) |
(dst.cc_swz[1] << NV40_FP_OP_COND_SWZ_Y_SHIFT) |
(dst.cc_swz[2] << NV40_FP_OP_COND_SWZ_Z_SHIFT) |
(dst.cc_swz[3] << NV40_FP_OP_COND_SWZ_W_SHIFT));
emit_dst(fpc, hw, dst);
emit_src(fpc, hw, 0, s0);
emit_src(fpc, hw, 1, s1);
emit_src(fpc, hw, 2, s2);
fp->insn_len += 4;
if (fpc->inst_has_const) {
fp->consts[fp->num_consts].pipe_id = fpc->inst_const_id;
fp->consts[fp->num_consts].hw_id = fp->insn_len;
fp->num_consts++;
fp->insn_len += 4;
}
}
static void
nv40_fp_tex(struct nv40_fpc *fpc, int sat, int op, int unit,
struct nv40_sreg dst, int mask,
struct nv40_sreg s0, struct nv40_sreg s1, struct nv40_sreg s2)
{
struct nv40_fragment_program *fp = fpc->fp;
uint32_t *hw = &fp->insn[fp->insn_len];
nv40_fp_arith(fpc, sat, op, dst, mask, s0, s1, s2);
hw[0] |= (unit << NV40_FP_OP_TEX_UNIT_SHIFT);
}
static INLINE struct nv40_sreg
tgsi_src(struct nv40_fpc *fpc, const struct tgsi_full_src_register *fsrc)
{
struct nv40_sreg src;
uint type, index;
switch (fsrc->SrcRegister.File) {
case TGSI_FILE_INPUT:
type = NV40_FP_REG_TYPE_INPUT;
index = fpc->attrib_map[fsrc->SrcRegister.Index];
break;
case TGSI_FILE_CONSTANT:
type = NV40_FP_REG_TYPE_CONST;
index = fsrc->SrcRegister.Index;
break;
case TGSI_FILE_TEMPORARY:
type = NV40_FP_REG_TYPE_TEMP;
index = fsrc->SrcRegister.Index + 1;
if (fpc->high_temp < index)
fpc->high_temp = index;
break;
default:
NOUVEAU_ERR("bad src file\n");
break;
}
src = nv40_sr(0, type, index);
src.abs = fsrc->SrcRegisterExtMod.Absolute;
src.negate = fsrc->SrcRegister.Negate;
src.swz[0] = fsrc->SrcRegister.SwizzleX;
src.swz[1] = fsrc->SrcRegister.SwizzleY;
src.swz[2] = fsrc->SrcRegister.SwizzleZ;
src.swz[3] = fsrc->SrcRegister.SwizzleW;
return src;
}
static INLINE struct nv40_sreg
tgsi_dst(struct nv40_fpc *fpc, const struct tgsi_full_dst_register *fdst) {
int out, idx;
switch (fdst->DstRegister.File) {
case TGSI_FILE_OUTPUT:
out = 1;
if (fdst->DstRegister.Index == fpc->colour_id)
idx = 0;
else
idx = 1;
break;
case TGSI_FILE_TEMPORARY:
out = 0;
idx = fdst->DstRegister.Index + 1;
if (fpc->high_temp < idx)
fpc->high_temp = idx;
break;
case TGSI_FILE_NULL:
break;
default:
NOUVEAU_ERR("bad dst file %d\n", fdst->DstRegister.File);
break;
}
return nv40_sr(out, NV40_FP_REG_TYPE_TEMP, idx);
}
static INLINE int
tgsi_mask(uint tgsi)
{
int mask = 0;
if (tgsi & TGSI_WRITEMASK_X) mask |= MASK_X;
if (tgsi & TGSI_WRITEMASK_Y) mask |= MASK_Y;
if (tgsi & TGSI_WRITEMASK_Z) mask |= MASK_Z;
if (tgsi & TGSI_WRITEMASK_W) mask |= MASK_W;
return mask;
}
static boolean
nv40_fragprog_parse_instruction(struct nv40_fpc *fpc,
const struct tgsi_full_instruction *finst)
{
struct nv40_sreg src[3], dst, tmp;
struct nv40_sreg none = nv40_sr(0, NV40_FP_REG_TYPE_INPUT, 0);
int mask, sat, unit;
int ai = -1, ci = -1;
int i;
if (finst->Instruction.Opcode == TGSI_OPCODE_RET)
return TRUE;
fpc->temp_temp_count = 0;
for (i = 0; i < finst->Instruction.NumSrcRegs; i++) {
const struct tgsi_full_src_register *fsrc;
fsrc = &finst->FullSrcRegisters[i];
if (fsrc->SrcRegister.File == TGSI_FILE_TEMPORARY) {
src[i] = tgsi_src(fpc, fsrc);
}
}
for (i = 0; i < finst->Instruction.NumSrcRegs; i++) {
const struct tgsi_full_src_register *fsrc;
fsrc = &finst->FullSrcRegisters[i];
switch (fsrc->SrcRegister.File) {
case TGSI_FILE_INPUT:
if (ai == -1 || ai == fsrc->SrcRegister.Index) {
ai = fsrc->SrcRegister.Index;
src[i] = tgsi_src(fpc, fsrc);
} else {
NOUVEAU_MSG("extra src attr %d\n",
fsrc->SrcRegister.Index);
src[i] = temp(fpc);
arith(fpc, 0, MOV, src[i], MASK_ALL,
tgsi_src(fpc, fsrc), none, none);
}
break;
case TGSI_FILE_CONSTANT:
if (ci == -1 || ci == fsrc->SrcRegister.Index) {
ci = fsrc->SrcRegister.Index;
src[i] = tgsi_src(fpc, fsrc);
} else {
src[i] = temp(fpc);
arith(fpc, 0, MOV, src[i], MASK_ALL,
tgsi_src(fpc, fsrc), none, none);
}
break;
case TGSI_FILE_TEMPORARY:
/* handled above */
break;
case TGSI_FILE_SAMPLER:
unit = fsrc->SrcRegister.Index;
break;
default:
NOUVEAU_ERR("bad src file\n");
return FALSE;
}
}
dst = tgsi_dst(fpc, &finst->FullDstRegisters[0]);
mask = tgsi_mask(finst->FullDstRegisters[0].DstRegister.WriteMask);
sat = (finst->Instruction.Saturate == TGSI_SAT_ZERO_ONE);
switch (finst->Instruction.Opcode) {
case TGSI_OPCODE_ABS:
arith(fpc, sat, MOV, dst, mask, abs(src[0]), none, none);
break;
case TGSI_OPCODE_ADD:
arith(fpc, sat, ADD, dst, mask, src[0], src[1], none);
break;
case TGSI_OPCODE_CMP:
tmp = temp(fpc);
arith(fpc, sat, MOV, dst, mask, src[2], none, none);
tmp.cc_update = 1;
arith(fpc, 0, MOV, tmp, 0xf, src[0], none, none);
dst.cc_test = NV40_VP_INST_COND_LT;
arith(fpc, sat, MOV, dst, mask, src[1], none, none);
break;
case TGSI_OPCODE_COS:
arith(fpc, sat, COS, dst, mask, src[0], none, none);
break;
case TGSI_OPCODE_DP3:
arith(fpc, sat, DP3, dst, mask, src[0], src[1], none);
break;
case TGSI_OPCODE_DP4:
arith(fpc, sat, DP4, dst, mask, src[0], src[1], none);
break;
case TGSI_OPCODE_DPH:
tmp = temp(fpc);
arith(fpc, 0, DP3, tmp, MASK_X, src[0], src[1], none);
arith(fpc, sat, ADD, dst, mask, swz(tmp, X, X, X, X),
swz(src[1], W, W, W, W), none);
break;
case TGSI_OPCODE_DST:
arith(fpc, sat, DST, dst, mask, src[0], src[1], none);
break;
case TGSI_OPCODE_EX2:
arith(fpc, sat, EX2, dst, mask, src[0], none, none);
break;
case TGSI_OPCODE_FLR:
arith(fpc, sat, FLR, dst, mask, src[0], none, none);
break;
case TGSI_OPCODE_FRC:
arith(fpc, sat, FRC, dst, mask, src[0], none, none);
break;
case TGSI_OPCODE_KIL:
case TGSI_OPCODE_KILP:
/*XXX: Which is NV, which is ARB kil? ARB implemented here.
*XXX: Don't need temp, can update CC0 without writing dst
*/
tmp = temp(fpc);
tmp.cc_update = 1;
arith(fpc, 0, MOV, tmp, MASK_ALL, src[0], none, none);
dst.cc_test = NV40_FP_OP_COND_LT;
arith(fpc, 0, KIL, dst, 0, none, none, none);
break;
case TGSI_OPCODE_LG2:
arith(fpc, sat, LG2, dst, mask, src[0], none, none);
break;
// case TGSI_OPCODE_LIT:
case TGSI_OPCODE_LRP:
tmp = temp(fpc);
arith(fpc, 0, MAD, tmp, mask, neg(src[0]), src[2], src[2]);
arith(fpc, sat, MAD, dst, mask, src[0], src[1], tmp);
break;
case TGSI_OPCODE_MAD:
arith(fpc, sat, MAD, dst, mask, src[0], src[1], src[2]);
break;
case TGSI_OPCODE_MAX:
arith(fpc, sat, MAX, dst, mask, src[0], src[1], none);
break;
case TGSI_OPCODE_MIN:
arith(fpc, sat, MIN, dst, mask, src[0], src[1], none);
break;
case TGSI_OPCODE_MOV:
arith(fpc, sat, MOV, dst, mask, src[0], none, none);
break;
case TGSI_OPCODE_MUL:
arith(fpc, sat, MUL, dst, mask, src[0], src[1], none);
break;
case TGSI_OPCODE_POW:
tmp = temp(fpc);
arith(fpc, 0, LG2, tmp, MASK_X,
swz(src[0], X, X, X, X), none, none);
arith(fpc, 0, MUL, tmp, MASK_X, swz(tmp, X, X, X, X),
swz(src[1], X, X, X, X), none);
arith(fpc, sat, EX2, dst, mask,
swz(tmp, X, X, X, X), none, none);
break;
case TGSI_OPCODE_RCP:
arith(fpc, sat, RCP, dst, mask, src[0], none, none);
break;
case TGSI_OPCODE_RFL:
tmp = temp(fpc);
arith(fpc, 0, DP3, tmp, MASK_X, src[0], src[0], none);
arith(fpc, 0, DP3, tmp, MASK_Y, src[0], src[1], none);
arith(fpc, 0, DIV, scale(tmp, 2X), MASK_Z,
swz(tmp, Y, Y, Y, Y), swz(tmp, X, X, X, X), none);
arith(fpc, sat, MAD, dst, mask,
swz(tmp, Z, Z, Z, Z), src[0], neg(src[1]));
break;
case TGSI_OPCODE_RSQ:
tmp = temp(fpc);
arith(fpc, 0, LG2, scale(tmp, INV_2X), MASK_X,
abs(swz(src[0], X, X, X, X)), none, none);
arith(fpc, sat, EX2, dst, mask,
neg(swz(tmp, X, X, X, X)), none, none);
break;
case TGSI_OPCODE_SCS:
if (mask & MASK_X) {
arith(fpc, sat, COS, dst, MASK_X,
swz(src[0], X, X, X, X), none, none);
}
if (mask & MASK_Y) {
arith(fpc, sat, SIN, dst, MASK_Y,
swz(src[0], X, X, X, X), none, none);
}
break;
case TGSI_OPCODE_SIN:
arith(fpc, sat, SIN, dst, mask, src[0], none, none);
break;
case TGSI_OPCODE_SGE:
arith(fpc, sat, SGE, dst, mask, src[0], src[1], none);
break;
case TGSI_OPCODE_SLT:
arith(fpc, sat, SLT, dst, mask, src[0], src[1], none);
break;
case TGSI_OPCODE_SUB:
arith(fpc, sat, ADD, dst, mask, src[0], neg(src[1]), none);
break;
case TGSI_OPCODE_TEX:
tex(fpc, sat, TEX, unit, dst, mask, src[0], none, none);
break;
case TGSI_OPCODE_TXB:
tex(fpc, sat, TXB, unit, dst, mask, src[0], none, none);
break;
#if 0 /* XXX: reimplement on top of TEX */
case TGSI_OPCODE_TXP:
tex(fpc, sat, TXP, unit, dst, mask, src[0], none, none);
break;
#endif
case TGSI_OPCODE_XPD:
tmp = temp(fpc);
arith(fpc, 0, MUL, tmp, mask,
swz(src[0], Z, X, Y, Y), swz(src[1], Y, Z, X, X), none);
arith(fpc, sat, MAD, dst, (mask & ~MASK_W),
swz(src[0], Y, Z, X, X), swz(src[1], Z, X, Y, Y),
neg(tmp));
break;
default:
NOUVEAU_ERR("invalid opcode %d\n", finst->Instruction.Opcode);
return FALSE;
}
return TRUE;
}
static boolean
nv40_fragprog_parse_decl_attrib(struct nv40_fpc *fpc,
const struct tgsi_full_declaration *fdec)
{
int hw;
switch (fdec->Semantic.SemanticName) {
case TGSI_SEMANTIC_POSITION:
hw = NV40_FP_OP_INPUT_SRC_POSITION;
break;
case TGSI_SEMANTIC_COLOR:
if (fdec->Semantic.SemanticIndex == 0) {
hw = NV40_FP_OP_INPUT_SRC_COL0;
} else
if (fdec->Semantic.SemanticIndex == 1) {
hw = NV40_FP_OP_INPUT_SRC_COL1;
} else {
NOUVEAU_ERR("bad colour semantic index\n");
return FALSE;
}
break;
case TGSI_SEMANTIC_FOG:
hw = NV40_FP_OP_INPUT_SRC_FOGC;
break;
case TGSI_SEMANTIC_GENERIC:
if (fdec->Semantic.SemanticIndex <= 7) {
hw = NV40_FP_OP_INPUT_SRC_TC(fdec->Semantic.
SemanticIndex);
} else {
NOUVEAU_ERR("bad generic semantic index\n");
return FALSE;
}
break;
default:
NOUVEAU_ERR("bad input semantic\n");
return FALSE;
}
fpc->attrib_map[fdec->u.DeclarationRange.First] = hw;
return TRUE;
}
static boolean
nv40_fragprog_parse_decl_output(struct nv40_fpc *fpc,
const struct tgsi_full_declaration *fdec)
{
switch (fdec->Semantic.SemanticName) {
case TGSI_SEMANTIC_POSITION:
fpc->depth_id = fdec->u.DeclarationRange.First;
break;
case TGSI_SEMANTIC_COLOR:
fpc->colour_id = fdec->u.DeclarationRange.First;
break;
default:
NOUVEAU_ERR("bad output semantic\n");
return FALSE;
}
return TRUE;
}
void
nv40_fragprog_translate(struct nv40_context *nv40,
struct nv40_fragment_program *fp)
{
struct tgsi_parse_context parse;
struct nv40_fpc *fpc = NULL;
int i;
fpc = calloc(1, sizeof(struct nv40_fpc));
if (!fpc)
return;
fp->insn = calloc(1, 128*4*sizeof(uint32_t));
fpc->fp = fp;
fpc->high_temp = -1;
fp->num_regs = 2;
tgsi_parse_init(&parse, fp->pipe->tokens);
while (!tgsi_parse_end_of_tokens(&parse)) {
tgsi_parse_token(&parse);
switch (parse.FullToken.Token.Type) {
case TGSI_TOKEN_TYPE_DECLARATION:
{
const struct tgsi_full_declaration *fdec;
fdec = &parse.FullToken.FullDeclaration;
switch (fdec->Declaration.File) {
case TGSI_FILE_INPUT:
if (!nv40_fragprog_parse_decl_attrib(fpc, fdec))
goto out_err;
break;
case TGSI_FILE_OUTPUT:
if (!nv40_fragprog_parse_decl_output(fpc, fdec))
goto out_err;
break;
default:
break;
}
}
break;
case TGSI_TOKEN_TYPE_IMMEDIATE:
break;
case TGSI_TOKEN_TYPE_INSTRUCTION:
{
const struct tgsi_full_instruction *finst;
finst = &parse.FullToken.FullInstruction;
if (!nv40_fragprog_parse_instruction(fpc, finst))
goto out_err;
}
break;
default:
break;
}
}
if (fpc->inst_has_const == FALSE)
fp->insn[fp->insn_len - 4] |= 0x00000001;
else
fp->insn[fp->insn_len - 8] |= 0x00000001;
fp->insn[fp->insn_len++] = 0x00000001;
fp->translated = TRUE;
fp->on_hw = FALSE;
out_err:
tgsi_parse_free(&parse);
free(fpc);
}
void
nv40_fragprog_bind(struct nv40_context *nv40, struct nv40_fragment_program *fp)
{
struct pipe_winsys *ws = nv40->pipe.winsys;
uint32_t fp_control;
if (!fp->translated) {
NOUVEAU_ERR("fragprog invalid, using passthrough shader\n");
fp = &passthrough_fp;
}
if (!fp->on_hw) {
if (!fp->buffer)
fp->buffer = ws->buffer_create(ws, 0x100);
nv40->pipe.winsys->buffer_data(nv40->pipe.winsys, fp->buffer,
fp->insn_len * sizeof(uint32_t),
fp->insn,
PIPE_BUFFER_USAGE_PIXEL);
fp->on_hw = TRUE;
}
fp_control = fp->num_regs << NV40TCL_FP_CONTROL_TEMP_COUNT_SHIFT;
if (fp->uses_kil)
fp_control |= NV40TCL_FP_CONTROL_KIL;
if (fp->writes_depth)
fp_control |= 0xe;
BEGIN_RING(curie, NV40TCL_FP_ADDRESS, 1);
OUT_RELOC (fp->buffer, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_GART |
NOUVEAU_BO_RD | NOUVEAU_BO_LOW | NOUVEAU_BO_OR,
NV40TCL_FP_ADDRESS_DMA0, NV40TCL_FP_ADDRESS_DMA1);
BEGIN_RING(curie, NV40TCL_FP_CONTROL, 1);
OUT_RING (fp_control);
nv40->fragprog.active_fp = fp;
}
+60
View File
@@ -0,0 +1,60 @@
#include "pipe/p_state.h"
#include "pipe/p_defines.h"
#include "pipe/p_util.h"
#include "nv40_context.h"
boolean
nv40_miptree_layout(struct pipe_context *pipe, struct pipe_mipmap_tree *mt)
{
struct nv40_context *nv40 = (struct nv40_context *)pipe;
uint width, height, depth, offset;
boolean swizzled = FALSE;
int l;
mt->pitch = mt->width0;
mt->total_height = 0;
width = mt->width0;
height = mt->height0;
depth = mt->depth0;
offset = 0;
for (l = mt->first_level; l <= mt->last_level; l++) {
uint pitch, f;
mt->level[l].width = width;
mt->level[l].height = height;
mt->level[l].depth = depth;
mt->level[l].level_offset = offset;
if (!swizzled)
pitch = mt->width0;
else
pitch = width;
if (mt->target == PIPE_TEXTURE_CUBE)
mt->level[l].nr_images = 6;
else
if (mt->target == PIPE_TEXTURE_3D)
mt->level[l].nr_images = 3;
else
mt->level[l].nr_images = 1;
mt->level[l].image_offset =
malloc(mt->level[l].nr_images * sizeof(unsigned));
for (f = 0; f < mt->level[l].nr_images; f++) {
mt->level[l].image_offset[f] =
(offset - mt->level[l].level_offset) / mt->cpp;
mt->total_height += height;
offset += (pitch * mt->cpp * height);
}
width = MAX2(1, width >> 1);
height = MAX2(1, height >> 1);
depth = MAX2(1, depth >> 1);
}
return TRUE;
}
+98
View File
@@ -0,0 +1,98 @@
#include "pipe/p_context.h"
#include "nv40_context.h"
#include "nv40_dma.h"
static uint
nv40_query_object_find(struct nv40_context *nv40, struct pipe_query_object *q)
{
int id;
for (id = 0; id < nv40->num_query_objects; id++) {
if (nv40->query_objects[id] == q)
return id;
}
return -1;
}
void
nv40_query_begin(struct pipe_context *pipe, struct pipe_query_object *q)
{
struct nv40_context *nv40 = (struct nv40_context *)pipe;
int id;
assert(q->type == PIPE_QUERY_OCCLUSION_COUNTER);
id = nv40_query_object_find(nv40, NULL);
assert(id >= 0);
nv40->query_objects[id] = q;
nv40->nvws->notifier_reset(nv40->query, id);
q->ready = 0;
BEGIN_RING(curie, NV40TCL_QUERY_RESET, 1);
OUT_RING (1);
BEGIN_RING(curie, NV40TCL_QUERY_UNK17CC, 1);
OUT_RING (1);
}
static void
nv40_query_update(struct pipe_context *pipe, struct pipe_query_object *q)
{
struct nv40_context *nv40 = (struct nv40_context *)pipe;
int id;
id = nv40_query_object_find(nv40, q);
assert(id >= 0);
if (nv40->nvws->notifier_status(nv40->query, id) == 0) {
q->ready = 1;
q->count = nv40->nvws->notifier_retval(nv40->query, id);
nv40->query_objects[id] = NULL;
}
}
void
nv40_query_end(struct pipe_context *pipe, struct pipe_query_object *q)
{
struct nv40_context *nv40 = (struct nv40_context *)pipe;
int id;
id = nv40_query_object_find(nv40, q);
assert(id >= 0);
BEGIN_RING(curie, NV40TCL_QUERY_GET, 1);
OUT_RING ((0x01 << NV40TCL_QUERY_GET_UNK24_SHIFT) |
((id * 32) << NV40TCL_QUERY_GET_OFFSET_SHIFT));
FIRE_RING ();
/*XXX: Some apps spin waiting for GL_QUERY_RESULT_AVAILABLE_ARB.
* Core mesa won't ask the driver to update the query object's
* status in this case, so the app waits forever.. fix this some
* day.
*/
#if 0
nv40_query_update(pipe, q);
#else
nv40_query_wait(pipe, q);
#endif
}
void
nv40_query_wait(struct pipe_context *pipe, struct pipe_query_object *q)
{
nv40_query_update(pipe, q);
if (!q->ready) {
struct nv40_context *nv40 = (struct nv40_context *)pipe;
int id;
id = nv40_query_object_find(nv40, q);
assert(id >= 0);
nv40->nvws->notifier_wait(nv40->query, id, 0, 0);
nv40_query_update(pipe, q);
assert(q->ready);
}
}
+85
View File
@@ -0,0 +1,85 @@
#include "pipe/p_defines.h"
#include "pipe/p_winsys.h"
#include "nv40_context.h"
#include "nv40_dma.h"
static ubyte *
nv40_region_map(struct pipe_context *pipe, struct pipe_region *region)
{
struct nv40_context *nv40 = (struct nv40_context *)pipe;
struct pipe_winsys *ws = nv40->pipe.winsys;
if (!region->map_refcount++) {
region->map = ws->buffer_map(ws, region->buffer,
PIPE_BUFFER_FLAG_WRITE |
PIPE_BUFFER_FLAG_READ);
}
return region->map;
}
static void
nv40_region_unmap(struct pipe_context *pipe, struct pipe_region *region)
{
struct nv40_context *nv40 = (struct nv40_context *)pipe;
struct pipe_winsys *ws = nv40->pipe.winsys;
if (!--region->map_refcount) {
ws->buffer_unmap(ws, region->buffer);
region->map = NULL;
}
}
static void
nv40_region_data(struct pipe_context *pipe,
struct pipe_region *dst,
unsigned dst_offset,
unsigned dstx, unsigned dsty,
const void *src, unsigned src_pitch,
unsigned srcx, unsigned srcy, unsigned width, unsigned height)
{
struct nv40_context *nv40 = (struct nv40_context *)pipe;
struct nouveau_winsys *nvws = nv40->nvws;
nvws->region_data(nvws->nv, dst, dst_offset, dstx, dsty,
src, src_pitch, srcx, srcy, width, height);
}
static void
nv40_region_copy(struct pipe_context *pipe, struct pipe_region *dst,
unsigned dst_offset, unsigned dstx, unsigned dsty,
struct pipe_region *src, unsigned src_offset,
unsigned srcx, unsigned srcy, unsigned width, unsigned height)
{
struct nv40_context *nv40 = (struct nv40_context *)pipe;
struct nouveau_winsys *nvws = nv40->nvws;
nvws->region_copy(nvws->nv, dst, dst_offset, dstx, dsty,
src, src_offset, srcx, srcy, width, height);
}
static void
nv40_region_fill(struct pipe_context *pipe,
struct pipe_region *dst, unsigned dst_offset,
unsigned dstx, unsigned dsty,
unsigned width, unsigned height, unsigned value)
{
struct nv40_context *nv40 = (struct nv40_context *)pipe;
struct nouveau_winsys *nvws = nv40->nvws;
nvws->region_fill(nvws->nv, dst, dst_offset, dstx, dsty,
width, height, value);
}
void
nv40_init_region_functions(struct nv40_context *nv40)
{
nv40->pipe.region_map = nv40_region_map;
nv40->pipe.region_unmap = nv40_region_unmap;
nv40->pipe.region_data = nv40_region_data;
nv40->pipe.region_copy = nv40_region_copy;
nv40->pipe.region_fill = nv40_region_fill;
}
+546
View File
@@ -0,0 +1,546 @@
#ifndef __NV40_SHADER_H__
#define __NV40_SHADER_H__
/* Vertex programs instruction set
*
* The NV40 instruction set is very similar to NV30. Most fields are in
* a slightly different position in the instruction however.
*
* Merged instructions
* In some cases it is possible to put two instructions into one opcode
* slot. The rules for when this is OK is not entirely clear to me yet.
*
* There are separate writemasks and dest temp register fields for each
* grouping of instructions. There is however only one field with the
* ID of a result register. Writing to temp/result regs is selected by
* setting VEC_RESULT/SCA_RESULT.
*
* Temporary registers
* The source/dest temp register fields have been extended by 1 bit, to
* give a total of 32 temporary registers.
*
* Relative Addressing
* NV40 can use an address register to index into vertex attribute regs.
* This is done by putting the offset value into INPUT_SRC and setting
* the INDEX_INPUT flag.
*
* Conditional execution (see NV_vertex_program{2,3} for details)
* There is a second condition code register on NV40, it's use is enabled
* by setting the COND_REG_SELECT_1 flag.
*
* Texture lookup
* TODO
*/
/* ---- OPCODE BITS 127:96 / data DWORD 0 --- */
#define NV40_VP_INST_VEC_RESULT (1 << 30)
/* uncertain.. */
#define NV40_VP_INST_COND_UPDATE_ENABLE ((1 << 14)|1<<29)
/* use address reg as index into attribs */
#define NV40_VP_INST_INDEX_INPUT (1 << 27)
#define NV40_VP_INST_COND_REG_SELECT_1 (1 << 25)
#define NV40_VP_INST_ADDR_REG_SELECT_1 (1 << 24)
#define NV40_VP_INST_SRC2_ABS (1 << 23)
#define NV40_VP_INST_SRC1_ABS (1 << 22)
#define NV40_VP_INST_SRC0_ABS (1 << 21)
#define NV40_VP_INST_VEC_DEST_TEMP_SHIFT 15
#define NV40_VP_INST_VEC_DEST_TEMP_MASK (0x1F << 15)
#define NV40_VP_INST_COND_TEST_ENABLE (1 << 13)
#define NV40_VP_INST_COND_SHIFT 10
#define NV40_VP_INST_COND_MASK (0x7 << 10)
# define NV40_VP_INST_COND_FL 0
# define NV40_VP_INST_COND_LT 1
# define NV40_VP_INST_COND_EQ 2
# define NV40_VP_INST_COND_LE 3
# define NV40_VP_INST_COND_GT 4
# define NV40_VP_INST_COND_NE 5
# define NV40_VP_INST_COND_GE 6
# define NV40_VP_INST_COND_TR 7
#define NV40_VP_INST_COND_SWZ_X_SHIFT 8
#define NV40_VP_INST_COND_SWZ_X_MASK (3 << 8)
#define NV40_VP_INST_COND_SWZ_Y_SHIFT 6
#define NV40_VP_INST_COND_SWZ_Y_MASK (3 << 6)
#define NV40_VP_INST_COND_SWZ_Z_SHIFT 4
#define NV40_VP_INST_COND_SWZ_Z_MASK (3 << 4)
#define NV40_VP_INST_COND_SWZ_W_SHIFT 2
#define NV40_VP_INST_COND_SWZ_W_MASK (3 << 2)
#define NV40_VP_INST_COND_SWZ_ALL_SHIFT 2
#define NV40_VP_INST_COND_SWZ_ALL_MASK (0xFF << 2)
#define NV40_VP_INST_ADDR_SWZ_SHIFT 0
#define NV40_VP_INST_ADDR_SWZ_MASK (0x03 << 0)
#define NV40_VP_INST0_KNOWN ( \
NV40_VP_INST_INDEX_INPUT | \
NV40_VP_INST_COND_REG_SELECT_1 | \
NV40_VP_INST_ADDR_REG_SELECT_1 | \
NV40_VP_INST_SRC2_ABS | \
NV40_VP_INST_SRC1_ABS | \
NV40_VP_INST_SRC0_ABS | \
NV40_VP_INST_VEC_DEST_TEMP_MASK | \
NV40_VP_INST_COND_TEST_ENABLE | \
NV40_VP_INST_COND_MASK | \
NV40_VP_INST_COND_SWZ_ALL_MASK | \
NV40_VP_INST_ADDR_SWZ_MASK)
/* ---- OPCODE BITS 95:64 / data DWORD 1 --- */
#define NV40_VP_INST_VEC_OPCODE_SHIFT 22
#define NV40_VP_INST_VEC_OPCODE_MASK (0x1F << 22)
# define NV40_VP_INST_OP_NOP 0x00
# define NV40_VP_INST_OP_MOV 0x01
# define NV40_VP_INST_OP_MUL 0x02
# define NV40_VP_INST_OP_ADD 0x03
# define NV40_VP_INST_OP_MAD 0x04
# define NV40_VP_INST_OP_DP3 0x05
# define NV40_VP_INST_OP_DP4 0x07
# define NV40_VP_INST_OP_DPH 0x06
# define NV40_VP_INST_OP_DST 0x08
# define NV40_VP_INST_OP_MIN 0x09
# define NV40_VP_INST_OP_MAX 0x0A
# define NV40_VP_INST_OP_SLT 0x0B
# define NV40_VP_INST_OP_SGE 0x0C
# define NV40_VP_INST_OP_ARL 0x0D
# define NV40_VP_INST_OP_FRC 0x0E
# define NV40_VP_INST_OP_FLR 0x0F
# define NV40_VP_INST_OP_SEQ 0x10
# define NV40_VP_INST_OP_SFL 0x11
# define NV40_VP_INST_OP_SGT 0x12
# define NV40_VP_INST_OP_SLE 0x13
# define NV40_VP_INST_OP_SNE 0x14
# define NV40_VP_INST_OP_STR 0x15
# define NV40_VP_INST_OP_SSG 0x16
# define NV40_VP_INST_OP_ARR 0x17
# define NV40_VP_INST_OP_ARA 0x18
# define NV40_VP_INST_OP_TXWHAT 0x19
#define NV40_VP_INST_SCA_OPCODE_SHIFT 27
#define NV40_VP_INST_SCA_OPCODE_MASK (0x1F << 27)
# define NV40_VP_INST_OP_RCP 0x02
# define NV40_VP_INST_OP_RCC 0x03
# define NV40_VP_INST_OP_RSQ 0x04
# define NV40_VP_INST_OP_EXP 0x05
# define NV40_VP_INST_OP_LOG 0x06
# define NV40_VP_INST_OP_LIT 0x07
# define NV40_VP_INST_OP_BRA 0x09
# define NV40_VP_INST_OP_CAL 0x0B
# define NV40_VP_INST_OP_RET 0x0C
# define NV40_VP_INST_OP_LG2 0x0D
# define NV40_VP_INST_OP_EX2 0x0E
# define NV40_VP_INST_OP_SIN 0x0F
# define NV40_VP_INST_OP_COS 0x10
# define NV40_VP_INST_OP_PUSHA 0x13
# define NV40_VP_INST_OP_POPA 0x14
#define NV40_VP_INST_CONST_SRC_SHIFT 12
#define NV40_VP_INST_CONST_SRC_MASK (0xFF << 12)
#define NV40_VP_INST_INPUT_SRC_SHIFT 8
#define NV40_VP_INST_INPUT_SRC_MASK (0x0F << 8)
# define NV40_VP_INST_IN_POS 0
# define NV40_VP_INST_IN_WEIGHT 1
# define NV40_VP_INST_IN_NORMAL 2
# define NV40_VP_INST_IN_COL0 3
# define NV40_VP_INST_IN_COL1 4
# define NV40_VP_INST_IN_FOGC 5
# define NV40_VP_INST_IN_TC0 8
# define NV40_VP_INST_IN_TC(n) (8+n)
#define NV40_VP_INST_SRC0H_SHIFT 0
#define NV40_VP_INST_SRC0H_MASK (0xFF << 0)
#define NV40_VP_INST1_KNOWN ( \
NV40_VP_INST_VEC_OPCODE_MASK | \
NV40_VP_INST_SCA_OPCODE_MASK | \
NV40_VP_INST_CONST_SRC_MASK | \
NV40_VP_INST_INPUT_SRC_MASK | \
NV40_VP_INST_SRC0H_MASK \
)
/* ---- OPCODE BITS 63:32 / data DWORD 2 --- */
#define NV40_VP_INST_SRC0L_SHIFT 23
#define NV40_VP_INST_SRC0L_MASK (0x1FF << 23)
#define NV40_VP_INST_SRC1_SHIFT 6
#define NV40_VP_INST_SRC1_MASK (0x1FFFF << 6)
#define NV40_VP_INST_SRC2H_SHIFT 0
#define NV40_VP_INST_SRC2H_MASK (0x3F << 0)
#define NV40_VP_INST_IADDRH_SHIFT 0
#define NV40_VP_INST_IADDRH_MASK (0x1F << 0)
/* ---- OPCODE BITS 31:0 / data DWORD 3 --- */
#define NV40_VP_INST_IADDRL_SHIFT 29
#define NV40_VP_INST_IADDRL_MASK (7 << 29)
#define NV40_VP_INST_SRC2L_SHIFT 21
#define NV40_VP_INST_SRC2L_MASK (0x7FF << 21)
#define NV40_VP_INST_SCA_WRITEMASK_SHIFT 17
#define NV40_VP_INST_SCA_WRITEMASK_MASK (0xF << 17)
# define NV40_VP_INST_SCA_WRITEMASK_X (1 << 20)
# define NV40_VP_INST_SCA_WRITEMASK_Y (1 << 19)
# define NV40_VP_INST_SCA_WRITEMASK_Z (1 << 18)
# define NV40_VP_INST_SCA_WRITEMASK_W (1 << 17)
#define NV40_VP_INST_VEC_WRITEMASK_SHIFT 13
#define NV40_VP_INST_VEC_WRITEMASK_MASK (0xF << 13)
# define NV40_VP_INST_VEC_WRITEMASK_X (1 << 16)
# define NV40_VP_INST_VEC_WRITEMASK_Y (1 << 15)
# define NV40_VP_INST_VEC_WRITEMASK_Z (1 << 14)
# define NV40_VP_INST_VEC_WRITEMASK_W (1 << 13)
#define NV40_VP_INST_SCA_RESULT (1 << 12)
#define NV40_VP_INST_SCA_DEST_TEMP_SHIFT 7
#define NV40_VP_INST_SCA_DEST_TEMP_MASK (0x1F << 7)
#define NV40_VP_INST_DEST_SHIFT 2
#define NV40_VP_INST_DEST_MASK (31 << 2)
# define NV40_VP_INST_DEST_POS 0
# define NV40_VP_INST_DEST_COL0 1
# define NV40_VP_INST_DEST_COL1 2
# define NV40_VP_INST_DEST_BFC0 3
# define NV40_VP_INST_DEST_BFC1 4
# define NV40_VP_INST_DEST_FOGC 5
# define NV40_VP_INST_DEST_PSZ 6
# define NV40_VP_INST_DEST_TC0 7
# define NV40_VP_INST_DEST_TC(n) (7+n)
# define NV40_VP_INST_DEST_TEMP 0x1F
#define NV40_VP_INST_INDEX_CONST (1 << 1)
#define NV40_VP_INST_LAST (1 << 0)
#define NV40_VP_INST3_KNOWN ( \
NV40_VP_INST_SRC2L_MASK |\
NV40_VP_INST_SCA_WRITEMASK_MASK |\
NV40_VP_INST_VEC_WRITEMASK_MASK |\
NV40_VP_INST_SCA_DEST_TEMP_MASK |\
NV40_VP_INST_DEST_MASK |\
NV40_VP_INST_INDEX_CONST)
/* Useful to split the source selection regs into their pieces */
#define NV40_VP_SRC0_HIGH_SHIFT 9
#define NV40_VP_SRC0_HIGH_MASK 0x0001FE00
#define NV40_VP_SRC0_LOW_MASK 0x000001FF
#define NV40_VP_SRC2_HIGH_SHIFT 11
#define NV40_VP_SRC2_HIGH_MASK 0x0001F800
#define NV40_VP_SRC2_LOW_MASK 0x000007FF
/* Source selection - these are the bits you fill NV40_VP_INST_SRCn with */
#define NV40_VP_SRC_NEGATE (1 << 16)
#define NV40_VP_SRC_SWZ_X_SHIFT 14
#define NV40_VP_SRC_SWZ_X_MASK (3 << 14)
#define NV40_VP_SRC_SWZ_Y_SHIFT 12
#define NV40_VP_SRC_SWZ_Y_MASK (3 << 12)
#define NV40_VP_SRC_SWZ_Z_SHIFT 10
#define NV40_VP_SRC_SWZ_Z_MASK (3 << 10)
#define NV40_VP_SRC_SWZ_W_SHIFT 8
#define NV40_VP_SRC_SWZ_W_MASK (3 << 8)
#define NV40_VP_SRC_SWZ_ALL_SHIFT 8
#define NV40_VP_SRC_SWZ_ALL_MASK (0xFF << 8)
#define NV40_VP_SRC_TEMP_SRC_SHIFT 2
#define NV40_VP_SRC_TEMP_SRC_MASK (0x1F << 2)
#define NV40_VP_SRC_REG_TYPE_SHIFT 0
#define NV40_VP_SRC_REG_TYPE_MASK (3 << 0)
# define NV40_VP_SRC_REG_TYPE_UNK0 0
# define NV40_VP_SRC_REG_TYPE_TEMP 1
# define NV40_VP_SRC_REG_TYPE_INPUT 2
# define NV40_VP_SRC_REG_TYPE_CONST 3
/*
* Each fragment program opcode appears to be comprised of 4 32-bit values.
*
* 0 - Opcode, output reg/mask, ATTRIB source
* 1 - Source 0
* 2 - Source 1
* 3 - Source 2
*
* There appears to be no special difference between result regs and temp regs.
* result.color == R0.xyzw
* result.depth == R1.z
* When the fragprog contains instructions to write depth,
* NV30_TCL_PRIMITIVE_3D_UNK1D78=0 otherwise it is set to 1.
*
* Constants are inserted directly after the instruction that uses them.
*
* It appears that it's not possible to use two input registers in one
* instruction as the input sourcing is done in the instruction dword
* and not the source selection dwords. As such instructions such as:
*
* ADD result.color, fragment.color, fragment.texcoord[0];
*
* must be split into two MOV's and then an ADD (nvidia does this) but
* I'm not sure why it's not just one MOV and then source the second input
* in the ADD instruction..
*
* Negation of the full source is done with NV30_FP_REG_NEGATE, arbitrary
* negation requires multiplication with a const.
*
* Arbitrary swizzling is supported with the exception of SWIZZLE_ZERO and
* SWIZZLE_ONE.
*
* The temp/result regs appear to be initialised to (0.0, 0.0, 0.0, 0.0) as
* SWIZZLE_ZERO is implemented simply by not writing to the relevant components
* of the destination.
*
* Looping
* Loops appear to be fairly expensive on NV40 at least, the proprietary
* driver goes to a lot of effort to avoid using the native looping
* instructions. If the total number of *executed* instructions between
* REP/ENDREP or LOOP/ENDLOOP is <=500, the driver will unroll the loop.
* The maximum loop count is 255.
*
* Conditional execution
* TODO
*
* Non-native instructions:
* LIT
* LRP - MAD+MAD
* SUB - ADD, negate second source
* RSQ - LG2 + EX2
* POW - LG2 + MUL + EX2
* SCS - COS + SIN
* XPD
* DP2 - MUL + ADD
* NRM
*/
//== Opcode / Destination selection ==
#define NV40_FP_OP_PROGRAM_END (1 << 0)
#define NV40_FP_OP_OUT_REG_SHIFT 1
#define NV40_FP_OP_OUT_REG_MASK (31 << 1)
/* Needs to be set when writing outputs to get expected result.. */
#define NV40_FP_OP_UNK0_7 (1 << 7)
#define NV40_FP_OP_COND_WRITE_ENABLE (1 << 8)
#define NV40_FP_OP_OUTMASK_SHIFT 9
#define NV40_FP_OP_OUTMASK_MASK (0xF << 9)
# define NV40_FP_OP_OUT_X (1 << 9)
# define NV40_FP_OP_OUT_Y (1 <<10)
# define NV40_FP_OP_OUT_Z (1 <<11)
# define NV40_FP_OP_OUT_W (1 <<12)
/* Uncertain about these, especially the input_src values.. it's possible that
* they can be dynamically changed.
*/
#define NV40_FP_OP_INPUT_SRC_SHIFT 13
#define NV40_FP_OP_INPUT_SRC_MASK (15 << 13)
# define NV40_FP_OP_INPUT_SRC_POSITION 0x0
# define NV40_FP_OP_INPUT_SRC_COL0 0x1
# define NV40_FP_OP_INPUT_SRC_COL1 0x2
# define NV40_FP_OP_INPUT_SRC_FOGC 0x3
# define NV40_FP_OP_INPUT_SRC_TC0 0x4
# define NV40_FP_OP_INPUT_SRC_TC(n) (0x4 + n)
# define NV40_FP_OP_INPUT_SRC_FACING 0xE
#define NV40_FP_OP_TEX_UNIT_SHIFT 17
#define NV40_FP_OP_TEX_UNIT_MASK (0xF << 17)
#define NV40_FP_OP_PRECISION_SHIFT 22
#define NV40_FP_OP_PRECISION_MASK (3 << 22)
# define NV40_FP_PRECISION_FP32 0
# define NV40_FP_PRECISION_FP16 1
# define NV40_FP_PRECISION_FX12 2
#define NV40_FP_OP_OPCODE_SHIFT 24
#define NV40_FP_OP_OPCODE_MASK (0x3F << 24)
# define NV40_FP_OP_OPCODE_NOP 0x00
# define NV40_FP_OP_OPCODE_MOV 0x01
# define NV40_FP_OP_OPCODE_MUL 0x02
# define NV40_FP_OP_OPCODE_ADD 0x03
# define NV40_FP_OP_OPCODE_MAD 0x04
# define NV40_FP_OP_OPCODE_DP3 0x05
# define NV40_FP_OP_OPCODE_DP4 0x06
# define NV40_FP_OP_OPCODE_DST 0x07
# define NV40_FP_OP_OPCODE_MIN 0x08
# define NV40_FP_OP_OPCODE_MAX 0x09
# define NV40_FP_OP_OPCODE_SLT 0x0A
# define NV40_FP_OP_OPCODE_SGE 0x0B
# define NV40_FP_OP_OPCODE_SLE 0x0C
# define NV40_FP_OP_OPCODE_SGT 0x0D
# define NV40_FP_OP_OPCODE_SNE 0x0E
# define NV40_FP_OP_OPCODE_SEQ 0x0F
# define NV40_FP_OP_OPCODE_FRC 0x10
# define NV40_FP_OP_OPCODE_FLR 0x11
# define NV40_FP_OP_OPCODE_KIL 0x12
# define NV40_FP_OP_OPCODE_PK4B 0x13
# define NV40_FP_OP_OPCODE_UP4B 0x14
/* DDX/DDY can only write to XY */
# define NV40_FP_OP_OPCODE_DDX 0x15
# define NV40_FP_OP_OPCODE_DDY 0x16
# define NV40_FP_OP_OPCODE_TEX 0x17
# define NV40_FP_OP_OPCODE_TXP 0x18
# define NV40_FP_OP_OPCODE_TXD 0x19
# define NV40_FP_OP_OPCODE_RCP 0x1A
# define NV40_FP_OP_OPCODE_EX2 0x1C
# define NV40_FP_OP_OPCODE_LG2 0x1D
# define NV40_FP_OP_OPCODE_COS 0x22
# define NV40_FP_OP_OPCODE_SIN 0x23
# define NV40_FP_OP_OPCODE_PK2H 0x24
# define NV40_FP_OP_OPCODE_UP2H 0x25
# define NV40_FP_OP_OPCODE_PK4UB 0x27
# define NV40_FP_OP_OPCODE_UP4UB 0x28
# define NV40_FP_OP_OPCODE_PK2US 0x29
# define NV40_FP_OP_OPCODE_UP2US 0x2A
# define NV40_FP_OP_OPCODE_DP2A 0x2E
# define NV40_FP_OP_OPCODE_TXL 0x2F
# define NV40_FP_OP_OPCODE_TXB 0x31
# define NV40_FP_OP_OPCODE_DIV 0x3A
# define NV40_FP_OP_OPCODE_UNK_LIT 0x3C
/* The use of these instructions appears to be indicated by bit 31 of DWORD 2.*/
# define NV40_FP_OP_BRA_OPCODE_BRK 0x0
# define NV40_FP_OP_BRA_OPCODE_CAL 0x1
# define NV40_FP_OP_BRA_OPCODE_IF 0x2
# define NV40_FP_OP_BRA_OPCODE_LOOP 0x3
# define NV40_FP_OP_BRA_OPCODE_REP 0x4
# define NV40_FP_OP_BRA_OPCODE_RET 0x5
#define NV40_FP_OP_OUT_SAT (1 << 31)
/* high order bits of SRC0 */
#define NV40_FP_OP_OUT_ABS (1 << 29)
#define NV40_FP_OP_COND_SWZ_W_SHIFT 27
#define NV40_FP_OP_COND_SWZ_W_MASK (3 << 27)
#define NV40_FP_OP_COND_SWZ_Z_SHIFT 25
#define NV40_FP_OP_COND_SWZ_Z_MASK (3 << 25)
#define NV40_FP_OP_COND_SWZ_Y_SHIFT 23
#define NV40_FP_OP_COND_SWZ_Y_MASK (3 << 23)
#define NV40_FP_OP_COND_SWZ_X_SHIFT 21
#define NV40_FP_OP_COND_SWZ_X_MASK (3 << 21)
#define NV40_FP_OP_COND_SWZ_ALL_SHIFT 21
#define NV40_FP_OP_COND_SWZ_ALL_MASK (0xFF << 21)
#define NV40_FP_OP_COND_SHIFT 18
#define NV40_FP_OP_COND_MASK (0x07 << 18)
# define NV40_FP_OP_COND_FL 0
# define NV40_FP_OP_COND_LT 1
# define NV40_FP_OP_COND_EQ 2
# define NV40_FP_OP_COND_LE 3
# define NV40_FP_OP_COND_GT 4
# define NV40_FP_OP_COND_NE 5
# define NV40_FP_OP_COND_GE 6
# define NV40_FP_OP_COND_TR 7
/* high order bits of SRC1 */
#define NV40_FP_OP_OPCODE_IS_BRANCH (1<<31)
#define NV40_FP_OP_DST_SCALE_SHIFT 28
#define NV40_FP_OP_DST_SCALE_MASK (3 << 28)
#define NV40_FP_OP_DST_SCALE_1X 0
#define NV40_FP_OP_DST_SCALE_2X 1
#define NV40_FP_OP_DST_SCALE_4X 2
#define NV40_FP_OP_DST_SCALE_8X 3
#define NV40_FP_OP_DST_SCALE_INV_2X 5
#define NV40_FP_OP_DST_SCALE_INV_4X 6
#define NV40_FP_OP_DST_SCALE_INV_8X 7
/* SRC1 LOOP */
#define NV40_FP_OP_LOOP_INCR_SHIFT 19
#define NV40_FP_OP_LOOP_INCR_MASK (0xFF << 19)
#define NV40_FP_OP_LOOP_INDEX_SHIFT 10
#define NV40_FP_OP_LOOP_INDEX_MASK (0xFF << 10)
#define NV40_FP_OP_LOOP_COUNT_SHIFT 2
#define NV40_FP_OP_LOOP_COUNT_MASK (0xFF << 2)
/* SRC1 IF */
#define NV40_FP_OP_ELSE_ID_SHIFT 2
#define NV40_FP_OP_ELSE_ID_MASK (0xFF << 2)
/* SRC1 CAL */
#define NV40_FP_OP_IADDR_SHIFT 2
#define NV40_FP_OP_IADDR_MASK (0xFF << 2)
/* SRC1 REP
* I have no idea why there are 3 count values here.. but they
* have always been filled with the same value in my tests so
* far..
*/
#define NV40_FP_OP_REP_COUNT1_SHIFT 2
#define NV40_FP_OP_REP_COUNT1_MASK (0xFF << 2)
#define NV40_FP_OP_REP_COUNT2_SHIFT 10
#define NV40_FP_OP_REP_COUNT2_MASK (0xFF << 10)
#define NV40_FP_OP_REP_COUNT3_SHIFT 19
#define NV40_FP_OP_REP_COUNT3_MASK (0xFF << 19)
/* SRC2 REP/IF */
#define NV40_FP_OP_END_ID_SHIFT 2
#define NV40_FP_OP_END_ID_MASK (0xFF << 2)
// SRC2 high-order
#define NV40_FP_OP_INDEX_INPUT (1 << 30)
#define NV40_FP_OP_ADDR_INDEX_SHIFT 19
#define NV40_FP_OP_ADDR_INDEX_MASK (0xF << 19)
//== Register selection ==
#define NV40_FP_REG_TYPE_SHIFT 0
#define NV40_FP_REG_TYPE_MASK (3 << 0)
# define NV40_FP_REG_TYPE_TEMP 0
# define NV40_FP_REG_TYPE_INPUT 1
# define NV40_FP_REG_TYPE_CONST 2
#define NV40_FP_REG_SRC_SHIFT 2
#define NV40_FP_REG_SRC_MASK (31 << 2)
#define NV40_FP_REG_UNK_0 (1 << 8)
#define NV40_FP_REG_SWZ_ALL_SHIFT 9
#define NV40_FP_REG_SWZ_ALL_MASK (255 << 9)
#define NV40_FP_REG_SWZ_X_SHIFT 9
#define NV40_FP_REG_SWZ_X_MASK (3 << 9)
#define NV40_FP_REG_SWZ_Y_SHIFT 11
#define NV40_FP_REG_SWZ_Y_MASK (3 << 11)
#define NV40_FP_REG_SWZ_Z_SHIFT 13
#define NV40_FP_REG_SWZ_Z_MASK (3 << 13)
#define NV40_FP_REG_SWZ_W_SHIFT 15
#define NV40_FP_REG_SWZ_W_MASK (3 << 15)
# define NV40_FP_SWIZZLE_X 0
# define NV40_FP_SWIZZLE_Y 1
# define NV40_FP_SWIZZLE_Z 2
# define NV40_FP_SWIZZLE_W 3
#define NV40_FP_REG_NEGATE (1 << 17)
struct nv40_sreg {
int output;
int type;
int index;
int dst_scale;
int negate;
int abs;
int swz[4];
int cc_update;
int cc_update_reg;
int cc_test;
int cc_test_reg;
int cc_swz[4];
};
static INLINE struct nv40_sreg
nv40_sr(int out, int type, int index)
{
struct nv40_sreg temp = {
.output = out,
.type = type,
.index = index,
.dst_scale = DEF_SCALE,
.abs = 0,
.negate = 0,
.swz = { 0, 1, 2, 3 },
.cc_update = 0,
.cc_update_reg = 0,
.cc_test = DEF_CTEST,
.cc_test_reg = 0,
.cc_swz = { 0, 1, 2, 3 },
};
return temp;
}
static INLINE struct nv40_sreg
nv40_sr_swz(struct nv40_sreg src, int x, int y, int z, int w)
{
struct nv40_sreg dst = src;
dst.swz[SWZ_X] = src.swz[x];
dst.swz[SWZ_Y] = src.swz[y];
dst.swz[SWZ_Z] = src.swz[z];
dst.swz[SWZ_W] = src.swz[w];
return dst;
}
static INLINE struct nv40_sreg
nv40_sr_neg(struct nv40_sreg src)
{
src.negate = !src.negate;
return src;
}
static INLINE struct nv40_sreg
nv40_sr_abs(struct nv40_sreg src)
{
src.abs = 1;
return src;
}
static INLINE struct nv40_sreg
nv40_sr_scale(struct nv40_sreg src, int scale)
{
src.dst_scale = scale;
return src;
}
#endif
+674
View File
@@ -0,0 +1,674 @@
#include "pipe/p_state.h"
#include "pipe/p_defines.h"
#include "pipe/p_util.h"
#include "nv40_context.h"
#include "nv40_dma.h"
#include "nv40_state.h"
#include "nvgl_pipe.h"
static void *
nv40_alpha_test_state_create(struct pipe_context *pipe,
const struct pipe_alpha_test_state *cso)
{
struct nv40_alpha_test_state *at;
at = malloc(sizeof(struct nv40_alpha_test_state));
at->enabled = cso->enabled ? 1 : 0;
if (at->enabled) {
at->func = nvgl_comparison_op(cso->func);
at->ref = float_to_ubyte(cso->ref);
}
return (void *)at;
}
static void
nv40_alpha_test_state_bind(struct pipe_context *pipe, void *hwcso)
{
struct nv40_context *nv40 = (struct nv40_context *)pipe;
struct nv40_alpha_test_state *at = hwcso;
if (at->enabled) {
BEGIN_RING(curie, NV40TCL_ALPHA_TEST_ENABLE, 3);
OUT_RING (at->enabled);
OUT_RING (at->func);
OUT_RING (at->ref);
} else {
BEGIN_RING(curie, NV40TCL_ALPHA_TEST_ENABLE, 1);
OUT_RING (0);
}
}
static void
nv40_alpha_test_state_delete(struct pipe_context *pipe, void *hwcso)
{
free(hwcso);
}
static void *
nv40_blend_state_create(struct pipe_context *pipe,
const struct pipe_blend_state *cso)
{
struct nv40_blend_state *cb;
cb = malloc(sizeof(struct nv40_blend_state));
cb->b_enable = cso->blend_enable ? 1 : 0;
if (cb->b_enable) {
cb->b_srcfunc = ((nvgl_blend_func(cso->alpha_src_factor)<<16) |
(nvgl_blend_func(cso->rgb_src_factor)));
cb->b_dstfunc = ((nvgl_blend_func(cso->alpha_dst_factor)<<16) |
(nvgl_blend_func(cso->rgb_dst_factor)));
cb->b_eqn = ((nvgl_blend_eqn(cso->alpha_func) << 16) |
(nvgl_blend_eqn(cso->rgb_func)));
}
cb->l_enable = cso->logicop_enable ? 1 : 0;
if (cb->l_enable) {
cb->l_op = nvgl_logicop_func(cso->logicop_func);
}
cb->c_mask = (((cso->colormask & PIPE_MASK_A) ? (0x01<<24) : 0) |
((cso->colormask & PIPE_MASK_R) ? (0x01<<16) : 0) |
((cso->colormask & PIPE_MASK_G) ? (0x01<< 8) : 0) |
((cso->colormask & PIPE_MASK_B) ? (0x01<< 0) : 0));
cb->d_enable = cso->dither ? 1 : 0;
return (void *)cb;
}
static void
nv40_blend_state_bind(struct pipe_context *pipe, void *hwcso)
{
struct nv40_context *nv40 = (struct nv40_context *)pipe;
struct nv40_blend_state *cb = hwcso;
BEGIN_RING(curie, NV40TCL_DITHER_ENABLE, 1);
OUT_RING (cb->d_enable);
if (cb->b_enable) {
BEGIN_RING(curie, NV40TCL_BLEND_ENABLE, 3);
OUT_RING (cb->b_enable);
OUT_RING (cb->b_srcfunc);
OUT_RING (cb->b_dstfunc);
BEGIN_RING(curie, NV40TCL_BLEND_EQUATION, 2);
OUT_RING (cb->b_eqn);
OUT_RING (cb->c_mask);
} else {
BEGIN_RING(curie, NV40TCL_BLEND_ENABLE, 1);
OUT_RING (0);
}
if (cb->l_enable) {
BEGIN_RING(curie, NV40TCL_COLOR_LOGIC_OP_ENABLE, 2);
OUT_RING (cb->l_enable);
OUT_RING (cb->l_op);
} else {
BEGIN_RING(curie, NV40TCL_COLOR_LOGIC_OP_ENABLE, 1);
OUT_RING (0);
}
}
static void
nv40_blend_state_delete(struct pipe_context *pipe, void *hwcso)
{
free(hwcso);
}
static void *
nv40_sampler_state_create(struct pipe_context *pipe,
const struct pipe_sampler_state *cso)
{
struct nv40_sampler_state *ps;
ps = malloc(sizeof(struct nv40_sampler_state));
ps->wrap = ((nv40_tex_wrap_mode(cso->wrap_r) << 16) |
(nv40_tex_wrap_mode(cso->wrap_t) << 8) |
(nv40_tex_wrap_mode(cso->wrap_s) << 0));
ps->filt = ((nv40_tex_filter(cso->min_img_filter,
cso->min_mip_filter) << 16) |
(nv40_tex_filter(cso->mag_img_filter,
PIPE_TEX_MIPFILTER_NONE) << 24));
ps->bcol = ((float_to_ubyte(cso->border_color[3]) << 24) |
(float_to_ubyte(cso->border_color[0]) << 16) |
(float_to_ubyte(cso->border_color[1]) << 8) |
(float_to_ubyte(cso->border_color[2]) << 0));
return (void *)ps;
}
static void
nv40_sampler_state_bind(struct pipe_context *pipe, unsigned unit,
void *hwcso)
{
struct nv40_context *nv40 = (struct nv40_context *)pipe;
struct nv40_sampler_state *ps = hwcso;
nv40->tex_sampler[unit] = ps;
nv40->tex_dirty |= (1 << unit);
nv40->dirty |= NV40_NEW_TEXTURE;
}
static void
nv40_sampler_state_delete(struct pipe_context *pipe, void *hwcso)
{
free(hwcso);
}
static void *
nv40_rasterizer_state_create(struct pipe_context *pipe,
const struct pipe_rasterizer_state *cso)
{
struct nv40_rasterizer_state *rs;
/*XXX: ignored:
* light_twoside
* offset_cw/ccw -nohw
* scissor
* point_smooth -nohw
* multisample
* offset_units / offset_scale
*/
rs = malloc(sizeof(struct nv40_rasterizer_state));
rs->shade_model = cso->flatshade ? 0x1d00 : 0x1d01;
rs->line_width = (unsigned char)(cso->line_width * 8.0) & 0xff;
rs->line_smooth_en = cso->line_smooth ? 1 : 0;
rs->line_stipple_en = cso->line_stipple_enable ? 1 : 0;
rs->line_stipple = (cso->line_stipple_pattern << 16) |
cso->line_stipple_factor;
rs->point_size = *(uint32_t*)&cso->point_size;
rs->poly_smooth_en = cso->poly_smooth ? 1 : 0;
rs->poly_stipple_en = cso->poly_stipple_enable ? 1 : 0;
if (cso->front_winding == PIPE_WINDING_CCW) {
rs->front_face = 0x0901;
rs->poly_mode_front = nvgl_polygon_mode(cso->fill_ccw);
rs->poly_mode_back = nvgl_polygon_mode(cso->fill_cw);
} else {
rs->front_face = 0x0900;
rs->poly_mode_front = nvgl_polygon_mode(cso->fill_cw);
rs->poly_mode_back = nvgl_polygon_mode(cso->fill_ccw);
}
rs->cull_face_en = 0;
rs->cull_face = 0x0900;
switch (cso->cull_mode) {
case PIPE_WINDING_CCW:
rs->cull_face = 0x0901;
/* fall-through */
case PIPE_WINDING_CW:
rs->cull_face_en = 1;
break;
case PIPE_WINDING_NONE:
default:
break;
}
return (void *)rs;
}
static void
nv40_rasterizer_state_bind(struct pipe_context *pipe, void *hwcso)
{
struct nv40_context *nv40 = (struct nv40_context *)pipe;
struct nv40_rasterizer_state *rs = hwcso;
BEGIN_RING(curie, NV40TCL_SHADE_MODEL, 1);
OUT_RING (rs->shade_model);
BEGIN_RING(curie, NV40TCL_LINE_WIDTH, 2);
OUT_RING (rs->line_width);
OUT_RING (rs->line_smooth_en);
BEGIN_RING(curie, NV40TCL_LINE_STIPPLE_ENABLE, 2);
OUT_RING (rs->line_stipple_en);
OUT_RING (rs->line_stipple);
BEGIN_RING(curie, NV40TCL_POINT_SIZE, 1);
OUT_RING (rs->point_size);
BEGIN_RING(curie, NV40TCL_POLYGON_MODE_FRONT, 6);
OUT_RING (rs->poly_mode_front);
OUT_RING (rs->poly_mode_back);
OUT_RING (rs->cull_face);
OUT_RING (rs->front_face);
OUT_RING (rs->poly_smooth_en);
OUT_RING (rs->cull_face_en);
BEGIN_RING(curie, NV40TCL_POLYGON_STIPPLE_ENABLE, 1);
OUT_RING (rs->poly_stipple_en);
}
static void
nv40_rasterizer_state_delete(struct pipe_context *pipe, void *hwcso)
{
free(hwcso);
}
static void *
nv40_depth_stencil_state_create(struct pipe_context *pipe,
const struct pipe_depth_stencil_state *cso)
{
struct nv40_depth_stencil_state *zs;
/*XXX: ignored:
* depth.occlusion_count
* depth.clear
* stencil.clear_value
*/
zs = malloc(sizeof(struct nv40_depth_stencil_state));
zs->depth.func = nvgl_comparison_op(cso->depth.func);
zs->depth.write_enable = cso->depth.writemask ? 1 : 0;
zs->depth.test_enable = cso->depth.enabled ? 1 : 0;
zs->stencil.back.enable = cso->stencil.back_enabled ? 1 : 0;
zs->stencil.back.wmask = cso->stencil.write_mask[1];
zs->stencil.back.func =
nvgl_comparison_op(cso->stencil.back_func);
zs->stencil.back.ref = cso->stencil.ref_value[1];
zs->stencil.back.vmask = cso->stencil.value_mask[1];
zs->stencil.back.fail = nvgl_stencil_op(cso->stencil.back_fail_op);
zs->stencil.back.zfail = nvgl_stencil_op(cso->stencil.back_zfail_op);
zs->stencil.back.zpass = nvgl_stencil_op(cso->stencil.back_zpass_op);
zs->stencil.front.enable= cso->stencil.front_enabled ? 1 : 0;
zs->stencil.front.wmask = cso->stencil.write_mask[0];
zs->stencil.front.func =
nvgl_comparison_op(cso->stencil.front_func);
zs->stencil.front.ref = cso->stencil.ref_value[0];
zs->stencil.front.vmask = cso->stencil.value_mask[0];
zs->stencil.front.fail = nvgl_stencil_op(cso->stencil.front_fail_op);
zs->stencil.front.zfail = nvgl_stencil_op(cso->stencil.front_zfail_op);
zs->stencil.front.zpass = nvgl_stencil_op(cso->stencil.front_zpass_op);
return (void *)zs;
}
static void
nv40_depth_stencil_state_bind(struct pipe_context *pipe, void *hwcso)
{
struct nv40_context *nv40 = (struct nv40_context *)pipe;
struct nv40_depth_stencil_state *zs = hwcso;
BEGIN_RING(curie, NV40TCL_DEPTH_FUNC, 3);
OUT_RINGp ((uint32_t *)&zs->depth, 3);
BEGIN_RING(curie, NV40TCL_STENCIL_BACK_ENABLE, 16);
OUT_RINGp ((uint32_t *)&zs->stencil.back, 8);
OUT_RINGp ((uint32_t *)&zs->stencil.front, 8);
}
static void
nv40_depth_stencil_state_delete(struct pipe_context *pipe, void *hwcso)
{
free(hwcso);
}
static void *
nv40_vp_state_create(struct pipe_context *pipe,
const struct pipe_shader_state *cso)
{
struct nv40_vertex_program *vp;
vp = calloc(1, sizeof(struct nv40_vertex_program));
vp->pipe = cso;
return (void *)vp;
}
static void
nv40_vp_state_bind(struct pipe_context *pipe, void *hwcso)
{
struct nv40_context *nv40 = (struct nv40_context *)pipe;
struct nv40_vertex_program *vp = hwcso;
nv40->vertprog.vp = vp;
nv40->dirty |= NV40_NEW_VERTPROG;
}
static void
nv40_vp_state_delete(struct pipe_context *pipe, void *hwcso)
{
free(hwcso);
}
static void *
nv40_fp_state_create(struct pipe_context *pipe,
const struct pipe_shader_state *cso)
{
struct nv40_fragment_program *fp;
fp = calloc(1, sizeof(struct nv40_fragment_program));
fp->pipe = cso;
return (void *)fp;
}
static void
nv40_fp_state_bind(struct pipe_context *pipe, void *hwcso)
{
struct nv40_context *nv40 = (struct nv40_context *)pipe;
struct nv40_fragment_program *fp = hwcso;
nv40->fragprog.fp = fp;
nv40->dirty |= NV40_NEW_FRAGPROG;
}
static void
nv40_fp_state_delete(struct pipe_context *pipe, void *hwcso)
{
free(hwcso);
}
static void
nv40_set_blend_color(struct pipe_context *pipe,
const struct pipe_blend_color *bcol)
{
struct nv40_context *nv40 = (struct nv40_context *)pipe;
BEGIN_RING(curie, NV40TCL_BLEND_COLOR, 1);
OUT_RING ((float_to_ubyte(bcol->color[3]) << 24) |
(float_to_ubyte(bcol->color[0]) << 16) |
(float_to_ubyte(bcol->color[1]) << 8) |
(float_to_ubyte(bcol->color[2]) << 0));
}
static void
nv40_set_clip_state(struct pipe_context *pipe,
const struct pipe_clip_state *clip)
{
struct nv40_context *nv40 = (struct nv40_context *)pipe;
nv40->dirty |= NV40_NEW_VERTPROG;
}
static void
nv40_set_clear_color_state(struct pipe_context *pipe,
const struct pipe_clear_color_state *ccol)
{
struct nv40_context *nv40 = (struct nv40_context *)pipe;
BEGIN_RING(curie, NV40TCL_CLEAR_VALUE_COLOR, 1);
OUT_RING ((float_to_ubyte(ccol->color[3]) << 24) |
(float_to_ubyte(ccol->color[0]) << 16) |
(float_to_ubyte(ccol->color[1]) << 8) |
(float_to_ubyte(ccol->color[2]) << 0));
}
static void
nv40_set_constant_buffer(struct pipe_context *pipe, uint shader, uint index,
const struct pipe_constant_buffer *buf )
{
struct nv40_context *nv40 = (struct nv40_context *)pipe;
if (shader == PIPE_SHADER_VERTEX) {
nv40->vertprog.constant_buf = buf->buffer;
nv40->dirty |= NV40_NEW_VERTPROG;
} else
if (shader == PIPE_SHADER_FRAGMENT) {
nv40->fragprog.constant_buf = buf->buffer;
nv40->dirty |= NV40_NEW_FRAGPROG;
}
}
static void
nv40_set_feedback_state(struct pipe_context *pipe,
const struct pipe_feedback_state *feedback)
{
NOUVEAU_ERR("\n");
}
#define get_region(surf) ((surf) ? surf->region : NULL)
static void
nv40_set_framebuffer_state(struct pipe_context *pipe,
const struct pipe_framebuffer_state *fb)
{
struct nv40_context *nv40 = (struct nv40_context *)pipe;
struct nouveau_winsys *nvws = nv40->nvws;
struct pipe_region *region;
uint32_t rt_enable = 0, rt_format = 0;
if ((region = get_region(fb->cbufs[0]))) {
rt_enable |= NV40TCL_RT_ENABLE_COLOR0;
BEGIN_RING(curie, NV40TCL_DMA_COLOR0, 1);
OUT_RELOCo(region->buffer, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
BEGIN_RING(curie, NV40TCL_COLOR0_PITCH, 2);
OUT_RING (region->pitch * region->cpp);
OUT_RELOCl(region->buffer, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
}
if ((region = get_region(fb->cbufs[1]))) {
rt_enable |= NV40TCL_RT_ENABLE_COLOR1;
BEGIN_RING(curie, NV40TCL_DMA_COLOR1, 1);
OUT_RELOCo(region->buffer, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
BEGIN_RING(curie, NV40TCL_COLOR1_OFFSET, 2);
OUT_RELOCl(region->buffer, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
OUT_RING (region->pitch * region->cpp);
}
if ((region = get_region(fb->cbufs[2]))) {
rt_enable |= NV40TCL_RT_ENABLE_COLOR2;
BEGIN_RING(curie, NV40TCL_DMA_COLOR2, 1);
OUT_RELOCo(region->buffer, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
BEGIN_RING(curie, NV40TCL_COLOR2_OFFSET, 1);
OUT_RELOCl(region->buffer, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
BEGIN_RING(curie, NV40TCL_COLOR2_PITCH, 1);
OUT_RING (region->pitch * region->cpp);
}
if ((region = get_region(fb->cbufs[3]))) {
rt_enable |= NV40TCL_RT_ENABLE_COLOR3;
BEGIN_RING(curie, NV40TCL_DMA_COLOR3, 1);
OUT_RELOCo(region->buffer, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
BEGIN_RING(curie, NV40TCL_COLOR3_OFFSET, 1);
OUT_RELOCl(region->buffer, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
BEGIN_RING(curie, NV40TCL_COLOR3_PITCH, 1);
OUT_RING (region->pitch * region->cpp);
}
if ((region = get_region(fb->zbuf))) {
BEGIN_RING(curie, NV40TCL_DMA_ZETA, 1);
OUT_RELOCo(region->buffer,
NOUVEAU_BO_VRAM | NOUVEAU_BO_WR | NOUVEAU_BO_RD);
BEGIN_RING(curie, NV40TCL_ZETA_OFFSET, 1);
OUT_RELOCl(region->buffer, 0,
NOUVEAU_BO_VRAM | NOUVEAU_BO_WR | NOUVEAU_BO_RD);
BEGIN_RING(curie, NV40TCL_ZETA_PITCH, 1);
OUT_RING (region->pitch * region->cpp);
}
if (rt_enable & (NV40TCL_RT_ENABLE_COLOR1 | NV40TCL_RT_ENABLE_COLOR2 |
NV40TCL_RT_ENABLE_COLOR3))
rt_enable |= NV40TCL_RT_ENABLE_MRT;
BEGIN_RING(curie, NV40TCL_RT_ENABLE, 1);
OUT_RING (rt_enable);
if (0) {
#if 0
rt_format |= (log2width <<
NV40TCL_RT_FORMAT_LOG2_WIDTH_SHIFT);
rt_format |= (log2height <<
NV40TCL_RT_FORMAT_LOG2_HEIGHT_SHIFT);
#endif
rt_format |= (NV40TCL_RT_FORMAT_TYPE_SWIZZLED <<
NV40TCL_RT_FORMAT_TYPE_SHIFT);
} else {
rt_format |= (NV40TCL_RT_FORMAT_TYPE_LINEAR <<
NV40TCL_RT_FORMAT_TYPE_SHIFT);
}
if (fb->cbufs[0]->format == PIPE_FORMAT_U_R5_G6_B5) {
rt_format |= (NV40TCL_RT_FORMAT_COLOR_R5G6B5 <<
NV40TCL_RT_FORMAT_COLOR_SHIFT);
} else {
rt_format |= (NV40TCL_RT_FORMAT_COLOR_A8R8G8B8 <<
NV40TCL_RT_FORMAT_COLOR_SHIFT);
}
if (fb->zbuf && fb->zbuf->format == PIPE_FORMAT_U_Z16) {
rt_format |= (NV40TCL_RT_FORMAT_DEPTH_Z16 <<
NV40TCL_RT_FORMAT_DEPTH_SHIFT);
} else {
rt_format |= (NV40TCL_RT_FORMAT_DEPTH_Z24S8 <<
NV40TCL_RT_FORMAT_DEPTH_SHIFT);
}
BEGIN_RING(curie, NV40TCL_RT_HORIZ, 3);
OUT_RING ((fb->cbufs[0]->width << 16) | 0);
OUT_RING ((fb->cbufs[0]->height << 16) | 0);
OUT_RING (rt_format);
BEGIN_RING(curie, NV40TCL_VIEWPORT_HORIZ, 2);
OUT_RING ((fb->cbufs[0]->width << 16) | 0);
OUT_RING ((fb->cbufs[0]->height << 16) | 0);
BEGIN_RING(curie, NV40TCL_VIEWPORT_CLIP_HORIZ(0), 2);
OUT_RING (((fb->cbufs[0]->width - 1) << 16) | 0);
OUT_RING (((fb->cbufs[0]->height - 1) << 16) | 0);
}
static void
nv40_set_polygon_stipple(struct pipe_context *pipe,
const struct pipe_poly_stipple *stipple)
{
struct nv40_context *nv40 = (struct nv40_context *)pipe;
BEGIN_RING(curie, NV40TCL_POLYGON_STIPPLE_PATTERN(0), 32);
OUT_RINGp ((uint32_t *)stipple->stipple, 32);
}
static void
nv40_set_sampler_units(struct pipe_context *pipe,
uint num_samplers, const uint *units)
{
}
static void
nv40_set_scissor_state(struct pipe_context *pipe,
const struct pipe_scissor_state *s)
{
struct nv40_context *nv40 = (struct nv40_context *)pipe;
BEGIN_RING(curie, NV40TCL_SCISSOR_HORIZ, 2);
OUT_RING (((s->maxx - s->minx) << 16) | s->minx);
OUT_RING (((s->maxy - s->miny) << 16) | s->miny);
}
static void
nv40_set_texture_state(struct pipe_context *pipe, unsigned unit,
struct pipe_mipmap_tree *miptree)
{
struct nv40_context *nv40 = (struct nv40_context *)pipe;
nv40->tex_miptree[unit] = miptree;
nv40->tex_dirty |= unit;
nv40->dirty |= NV40_NEW_TEXTURE;
}
static void
nv40_set_viewport_state(struct pipe_context *pipe,
const struct pipe_viewport_state *vpt)
{
struct nv40_context *nv40 = (struct nv40_context *)pipe;
BEGIN_RING(curie, NV40TCL_VIEWPORT_TRANSLATE_X, 8);
OUT_RINGf (vpt->translate[0]);
OUT_RINGf (vpt->translate[1]);
OUT_RINGf (vpt->translate[2]);
OUT_RINGf (vpt->translate[3]);
OUT_RINGf (vpt->scale[0]);
OUT_RINGf (vpt->scale[1]);
OUT_RINGf (vpt->scale[2]);
OUT_RINGf (vpt->scale[3]);
}
static void
nv40_set_vertex_buffer(struct pipe_context *pipe, unsigned index,
const struct pipe_vertex_buffer *vb)
{
struct nv40_context *nv40 = (struct nv40_context *)pipe;
nv40->vtxbuf[index] = *vb;
nv40->dirty |= NV40_NEW_ARRAYS;
}
static void
nv40_set_vertex_element(struct pipe_context *pipe, unsigned index,
const struct pipe_vertex_element *ve)
{
struct nv40_context *nv40 = (struct nv40_context *)pipe;
nv40->vtxelt[index] = *ve;
nv40->dirty |= NV40_NEW_ARRAYS;
}
static void
nv40_set_feedback_buffer(struct pipe_context *pipe, unsigned index,
const struct pipe_feedback_buffer *fbb)
{
NOUVEAU_ERR("\n");
}
void
nv40_init_state_functions(struct nv40_context *nv40)
{
nv40->pipe.create_alpha_test_state = nv40_alpha_test_state_create;
nv40->pipe.bind_alpha_test_state = nv40_alpha_test_state_bind;
nv40->pipe.delete_alpha_test_state = nv40_alpha_test_state_delete;
nv40->pipe.create_blend_state = nv40_blend_state_create;
nv40->pipe.bind_blend_state = nv40_blend_state_bind;
nv40->pipe.delete_blend_state = nv40_blend_state_delete;
nv40->pipe.create_sampler_state = nv40_sampler_state_create;
nv40->pipe.bind_sampler_state = nv40_sampler_state_bind;
nv40->pipe.delete_sampler_state = nv40_sampler_state_delete;
nv40->pipe.create_rasterizer_state = nv40_rasterizer_state_create;
nv40->pipe.bind_rasterizer_state = nv40_rasterizer_state_bind;
nv40->pipe.delete_rasterizer_state = nv40_rasterizer_state_delete;
nv40->pipe.create_depth_stencil_state = nv40_depth_stencil_state_create;
nv40->pipe.bind_depth_stencil_state = nv40_depth_stencil_state_bind;
nv40->pipe.delete_depth_stencil_state = nv40_depth_stencil_state_delete;
nv40->pipe.create_vs_state = nv40_vp_state_create;
nv40->pipe.bind_vs_state = nv40_vp_state_bind;
nv40->pipe.delete_vs_state = nv40_vp_state_delete;
nv40->pipe.create_fs_state = nv40_fp_state_create;
nv40->pipe.bind_fs_state = nv40_fp_state_bind;
nv40->pipe.delete_fs_state = nv40_fp_state_delete;
nv40->pipe.set_blend_color = nv40_set_blend_color;
nv40->pipe.set_clip_state = nv40_set_clip_state;
nv40->pipe.set_clear_color_state = nv40_set_clear_color_state;
nv40->pipe.set_constant_buffer = nv40_set_constant_buffer;
// nv40->pipe.set_feedback_state = nv40_set_feedback_state;
nv40->pipe.set_framebuffer_state = nv40_set_framebuffer_state;
nv40->pipe.set_polygon_stipple = nv40_set_polygon_stipple;
nv40->pipe.set_sampler_units = nv40_set_sampler_units;
nv40->pipe.set_scissor_state = nv40_set_scissor_state;
nv40->pipe.set_texture_state = nv40_set_texture_state;
nv40->pipe.set_viewport_state = nv40_set_viewport_state;
nv40->pipe.set_vertex_buffer = nv40_set_vertex_buffer;
nv40->pipe.set_vertex_element = nv40_set_vertex_element;
// nv40->pipe.set_feedback_buffer = nv40_set_feedback_buffer;
}
+173
View File
@@ -0,0 +1,173 @@
#ifndef __NV40_STATE_H__
#define __NV40_STATE_H__
#include "pipe/p_state.h"
struct nv40_alpha_test_state {
uint32_t enabled;
uint32_t func;
uint32_t ref;
};
struct nv40_blend_state {
uint32_t b_enable;
uint32_t b_srcfunc;
uint32_t b_dstfunc;
uint32_t b_eqn;
uint32_t l_enable;
uint32_t l_op;
uint32_t c_mask;
uint32_t d_enable;
};
struct nv40_sampler_state {
uint32_t wrap;
uint32_t filt;
uint32_t bcol;
};
struct nv40_rasterizer_state {
uint32_t shade_model;
uint32_t line_width;
uint32_t line_smooth_en;
uint32_t line_stipple_en;
uint32_t line_stipple;
uint32_t point_size;
uint32_t poly_smooth_en;
uint32_t poly_stipple_en;
uint32_t poly_mode_front;
uint32_t poly_mode_back;
uint32_t front_face;
uint32_t cull_face;
uint32_t cull_face_en;
};
struct nv40_vertex_program {
const struct pipe_shader_state *pipe;
boolean translated;
boolean on_hw;
int start_ip;
uint32_t *insn;
int insn_len;
struct {
int pipe_id;
int hw_id;
float value[4];
} consts[256];
int num_consts;
uint32_t ir;
uint32_t or;
};
struct nv40_fragment_program {
const struct pipe_shader_state *pipe;
boolean translated;
boolean on_hw;
uint32_t *insn;
int insn_len;
struct {
int pipe_id;
int hw_id;
} consts[256];
int num_consts;
struct pipe_buffer_handle *buffer;
boolean uses_kil;
boolean writes_depth;
int num_regs;
};
struct nv40_depth_push {
uint32_t func;
uint32_t write_enable;
uint32_t test_enable;
};
struct nv40_stencil_push {
uint32_t enable;
uint32_t wmask;
uint32_t func;
uint32_t ref;
uint32_t vmask;
uint32_t fail;
uint32_t zfail;
uint32_t zpass;
};
struct nv40_depth_stencil_state {
struct nv40_depth_push depth;
union {
struct nv40_stencil_push back;
struct nv40_stencil_push front;
} stencil;
};
static INLINE unsigned
nv40_tex_wrap_mode(unsigned wrap) {
switch (wrap) {
case PIPE_TEX_WRAP_REPEAT:
return NV40TCL_TEX_WRAP_S_REPEAT;
case PIPE_TEX_WRAP_MIRROR_REPEAT:
return NV40TCL_TEX_WRAP_S_MIRRORED_REPEAT;
case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
return NV40TCL_TEX_WRAP_S_CLAMP_TO_EDGE;
case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
return NV40TCL_TEX_WRAP_S_CLAMP_TO_BORDER;
case PIPE_TEX_WRAP_CLAMP:
return NV40TCL_TEX_WRAP_S_CLAMP;
case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
return NV40TCL_TEX_WRAP_S_MIRROR_CLAMP_TO_EDGE;
case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
return NV40TCL_TEX_WRAP_S_MIRROR_CLAMP_TO_BORDER;
case PIPE_TEX_WRAP_MIRROR_CLAMP:
return NV40TCL_TEX_WRAP_S_MIRROR_CLAMP;
default:
return NV40TCL_TEX_WRAP_S_REPEAT;
}
}
static INLINE unsigned
nv40_tex_filter(unsigned f0, unsigned f1) {
switch (f0) {
case PIPE_TEX_FILTER_NEAREST:
switch (f1) {
case PIPE_TEX_MIPFILTER_NEAREST:
return NV40TCL_TEX_FILTER_MIN_NEAREST_MIPMAP_NEAREST;
case PIPE_TEX_MIPFILTER_LINEAR:
return NV40TCL_TEX_FILTER_MIN_NEAREST_MIPMAP_LINEAR;
case PIPE_TEX_MIPFILTER_NONE:
default:
return NV40TCL_TEX_FILTER_MIN_NEAREST;
}
case PIPE_TEX_FILTER_LINEAR:
default:
switch (f1) {
case PIPE_TEX_MIPFILTER_NEAREST:
return NV40TCL_TEX_FILTER_MIN_LINEAR_MIPMAP_NEAREST;
case PIPE_TEX_MIPFILTER_LINEAR:
return NV40TCL_TEX_FILTER_MIN_LINEAR_MIPMAP_LINEAR;
case PIPE_TEX_MIPFILTER_NONE:
default:
return NV40TCL_TEX_FILTER_MIN_LINEAR;
}
}
}
#endif
+112
View File
@@ -0,0 +1,112 @@
#include "nv40_context.h"
#include "nv40_dma.h"
#include "nv40_state.h"
static INLINE void
nv40_state_update_fragprog(struct nv40_context *nv40)
{
struct pipe_context *pipe = (struct pipe_context *)nv40;
struct nv40_fragment_program *fp = nv40->fragprog.fp;
float *map;
int i;
if (!fp->translated)
nv40_fragprog_translate(nv40, fp);
if (fp->num_consts) {
map = pipe->winsys->buffer_map(pipe->winsys,
nv40->fragprog.constant_buf,
PIPE_BUFFER_FLAG_READ);
for (i = 0; i < fp->num_consts; i++) {
uint pid = fp->consts[i].pipe_id;
if (pid == -1)
continue;
if (!memcmp(&fp->insn[fp->consts[i].hw_id], &map[pid*4],
4 * sizeof(float)))
continue;
memcpy(&fp->insn[fp->consts[i].hw_id], &map[pid*4],
4 * sizeof(float));
fp->on_hw = 0;
}
pipe->winsys->buffer_unmap(pipe->winsys,
nv40->fragprog.constant_buf);
}
}
static INLINE void
nv40_state_update_vertprog(struct nv40_context *nv40)
{
struct pipe_context *pipe = (struct pipe_context *)nv40;
struct nv40_vertex_program *vp = nv40->vertprog.vp;
float *map;
int i;
if (!nv40->vertprog.vp->translated)
nv40_vertprog_translate(nv40, nv40->vertprog.vp);
if (vp->num_consts) {
map = pipe->winsys->buffer_map(pipe->winsys,
nv40->vertprog.constant_buf,
PIPE_BUFFER_FLAG_READ);
for (i = 0; i < vp->num_consts; i++) {
uint pid = vp->consts[i].pipe_id;
if (pid >= 0) {
if (!memcmp(vp->consts[i].value, &map[pid*4],
4 * sizeof(float)))
continue;
memcpy(vp->consts[i].value, &map[pid*4],
4 * sizeof(float));
}
BEGIN_RING(curie, NV40TCL_VP_UPLOAD_CONST_ID, 5);
OUT_RING (vp->consts[i].hw_id);
OUT_RINGp ((uint32_t *)vp->consts[i].value, 4);
}
pipe->winsys->buffer_unmap(pipe->winsys,
nv40->vertprog.constant_buf);
}
}
void
nv40_emit_hw_state(struct nv40_context *nv40)
{
if (nv40->dirty & NV40_NEW_FRAGPROG) {
struct nv40_fragment_program *cur = nv40->fragprog.fp;
nv40_state_update_fragprog(nv40);
if (cur->on_hw)
nv40->dirty &= ~NV40_NEW_FRAGPROG;
if (!cur->on_hw || cur != nv40->fragprog.active_fp)
nv40_fragprog_bind(nv40, cur);
}
if (nv40->dirty & NV40_NEW_TEXTURE)
nv40_state_tex_update(nv40);
if (nv40->dirty & (NV40_NEW_TEXTURE | NV40_NEW_FRAGPROG)) {
BEGIN_RING(curie, NV40TCL_TEX_CACHE_CTL, 1);
OUT_RING (2);
BEGIN_RING(curie, NV40TCL_TEX_CACHE_CTL, 1);
OUT_RING (1);
nv40->dirty &= ~(NV40_NEW_TEXTURE | NV40_NEW_FRAGPROG);
}
if (nv40->dirty & NV40_NEW_VERTPROG) {
nv40_state_update_vertprog(nv40);
if (nv40->vertprog.vp != nv40->vertprog.active_vp)
nv40_vertprog_bind(nv40, nv40->vertprog.vp);
nv40->dirty &= ~NV40_NEW_VERTPROG;
}
if (nv40->dirty & NV40_NEW_ARRAYS) {
nv40_vbo_arrays_update(nv40);
nv40->dirty &= ~NV40_NEW_ARRAYS;
}
}
+140
View File
@@ -0,0 +1,140 @@
#include "nv40_context.h"
#include "nv40_dma.h"
#define _(m,tf,ts0x,ts0y,ts0z,ts0w,ts1x,ts1y,ts1z,ts1w) \
{ \
TRUE, \
PIPE_FORMAT_##m, \
NV40TCL_TEX_FORMAT_FORMAT_##tf, \
(NV40TCL_TEX_SWIZZLE_S0_X_##ts0x << NV40TCL_TEX_SWIZZLE_S0_X_SHIFT) | \
(NV40TCL_TEX_SWIZZLE_S0_X_##ts0y << NV40TCL_TEX_SWIZZLE_S0_Y_SHIFT) | \
(NV40TCL_TEX_SWIZZLE_S0_X_##ts0z << NV40TCL_TEX_SWIZZLE_S0_Z_SHIFT) | \
(NV40TCL_TEX_SWIZZLE_S0_X_##ts0w << NV40TCL_TEX_SWIZZLE_S0_W_SHIFT) | \
(NV40TCL_TEX_SWIZZLE_S1_X_##ts1x << NV40TCL_TEX_SWIZZLE_S1_X_SHIFT) | \
(NV40TCL_TEX_SWIZZLE_S1_X_##ts1y << NV40TCL_TEX_SWIZZLE_S1_Y_SHIFT) | \
(NV40TCL_TEX_SWIZZLE_S1_X_##ts1z << NV40TCL_TEX_SWIZZLE_S1_Z_SHIFT) | \
(NV40TCL_TEX_SWIZZLE_S1_X_##ts1w << NV40TCL_TEX_SWIZZLE_S1_W_SHIFT), \
}
struct nv40_texture_format {
boolean defined;
uint pipe;
int format;
int swizzle;
};
static struct nv40_texture_format
nv40_texture_formats[] = {
_(U_A8_R8_G8_B8, A8R8G8B8, S1, S1, S1, S1, X, Y, Z, W),
_(U_A1_R5_G5_B5, A1R5G5B5, S1, S1, S1, S1, X, Y, Z, W),
_(U_A4_R4_G4_B4, A4R4G4B4, S1, S1, S1, S1, X, Y, Z, W),
_(U_R5_G6_B5 , R5G6B5 , S1, S1, S1, ONE, X, Y, Z, W),
_(U_L8 , L8 , S1, S1, S1, ONE, X, X, X, X),
_(U_A8 , L8 , ZERO, ZERO, ZERO, S1, X, X, X, X),
_(U_I8 , L8 , S1, S1, S1, S1, X, X, X, X),
_(U_A8_L8 , A8L8 , S1, S1, S1, S1, Z, W, X, Y),
// _(RGB_DXT1 , 0x86, S1, S1, S1, ONE, X, Y, Z, W, 0x00, 0x00),
// _(RGBA_DXT1 , 0x86, S1, S1, S1, S1, X, Y, Z, W, 0x00, 0x00),
// _(RGBA_DXT3 , 0x87, S1, S1, S1, S1, X, Y, Z, W, 0x00, 0x00),
// _(RGBA_DXT5 , 0x88, S1, S1, S1, S1, X, Y, Z, W, 0x00, 0x00),
};
static struct nv40_texture_format *
nv40_tex_format(uint pipe_format)
{
struct nv40_texture_format *tf = nv40_texture_formats;
while (tf->defined) {
if (tf->pipe == pipe_format)
return tf;
tf++;
}
return NULL;
}
static INLINE int
nv40_tex_dims(uint pipe_target)
{
switch (pipe_target) {
case PIPE_TEXTURE_1D: return 1;
case PIPE_TEXTURE_2D: return 2;
case PIPE_TEXTURE_3D: return 3;
case PIPE_TEXTURE_CUBE: return 2;
default:
NOUVEAU_ERR("AII unknown pipe target: %d\n", pipe_target);
return 2;
}
}
static void
nv40_tex_unit_enable(struct nv40_context *nv40, int unit)
{
struct nouveau_winsys *nvws = nv40->nvws;
struct nv40_sampler_state *ps = nv40->tex_sampler[unit];
struct pipe_mipmap_tree *mt = nv40->tex_miptree[unit];
struct nv40_texture_format *tf;
uint32_t txf, txs, txp;
int swizzled = 0; /*XXX: implement in region code? */
tf = nv40_tex_format(mt->format);
if (!tf->defined) {
NOUVEAU_ERR("Unsupported texture format: 0x%x\n", mt->format);
return;
}
txf = (tf->format | 0x80) << NV40TCL_TEX_FORMAT_FORMAT_SHIFT;
txf |= ((mt->last_level - mt->first_level + 1) <<
NV40TCL_TEX_FORMAT_MIPMAP_COUNT_SHIFT);
if (1) /* XXX */
txf |= NV40TCL_TEX_FORMAT_NO_BORDER;
txf |= (nv40_tex_dims(mt->target) << NV40TCL_TEX_FORMAT_DIMS_SHIFT);
if (0) /*XXX*/
txf |= NV40TCL_TEX_FORMAT_RECT;
if (swizzled) {
txp = 0;
} else {
txp = mt->pitch * mt->cpp;
txf |= NV40TCL_TEX_FORMAT_LINEAR;
}
txs = tf->swizzle;
if (mt->format == PIPE_FORMAT_U_A8_L8)
txs |= (1<<16); /*nfi*/
BEGIN_RING(curie, NV40TCL_TEX_OFFSET(unit), 8);
OUT_RELOCl(mt->region->buffer, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_GART |
NOUVEAU_BO_RD);
OUT_RELOCd(mt->region->buffer, txf, NOUVEAU_BO_VRAM | NOUVEAU_BO_GART |
NOUVEAU_BO_OR | NOUVEAU_BO_RD, NV40TCL_TEX_FORMAT_DMA0,
NV40TCL_TEX_FORMAT_DMA1);
OUT_RING (ps->wrap);
OUT_RING (NV40TCL_TEX_ENABLE_ENABLE |
(0x00078000) /* mipmap related? */);
OUT_RING (txs);
OUT_RING (ps->filt | 0x3fd6 /*voodoo*/);
OUT_RING ((mt->width0 << NV40TCL_TEX_SIZE0_W_SHIFT) | mt->height0);
OUT_RING (ps->bcol);
BEGIN_RING(curie, NV40TCL_TEX_SIZE1(unit), 1);
OUT_RING ((mt->depth0 << NV40TCL_TEX_SIZE1_DEPTH_SHIFT) | txp);
}
void
nv40_state_tex_update(struct nv40_context *nv40)
{
while (nv40->tex_dirty) {
int unit = ffs(nv40->tex_dirty) - 1;
if (nv40->tex_miptree[unit]) {
nv40_tex_unit_enable(nv40, unit);
} else {
BEGIN_RING(curie, NV40TCL_TEX_ENABLE(unit), 1);
OUT_RING (0);
}
nv40->tex_dirty &= ~(1 << unit);
}
}
+229
View File
@@ -0,0 +1,229 @@
/**************************************************************************
*
* Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
* 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 above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* 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 TUNGSTEN GRAPHICS 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.
*
**************************************************************************/
#include "nv40_context.h"
#include "pipe/p_defines.h"
#include "pipe/p_util.h"
#include "pipe/p_winsys.h"
#include "pipe/p_inlines.h"
#define CLIP_TILE \
do { \
if (x >= ps->width) \
return; \
if (y >= ps->height) \
return; \
if (x + w > ps->width) \
w = ps->width - x; \
if (y + h > ps->height) \
h = ps->height -y; \
} while(0)
/**
* Note: this is exactly like a8r8g8b8_get_tile() in sp_surface.c
* Share it someday.
*/
static void
nv40_get_tile_rgba(struct pipe_context *pipe,
struct pipe_surface *ps,
uint x, uint y, uint w, uint h, float *p)
{
const unsigned *src
= ((const unsigned *) (ps->region->map + ps->offset))
+ y * ps->region->pitch + x;
unsigned i, j;
unsigned w0 = w;
CLIP_TILE;
switch (ps->format) {
case PIPE_FORMAT_U_A8_R8_G8_B8:
for (i = 0; i < h; i++) {
float *pRow = p;
for (j = 0; j < w; j++) {
const unsigned pixel = src[j];
pRow[0] = UBYTE_TO_FLOAT((pixel >> 16) & 0xff);
pRow[1] = UBYTE_TO_FLOAT((pixel >> 8) & 0xff);
pRow[2] = UBYTE_TO_FLOAT((pixel >> 0) & 0xff);
pRow[3] = UBYTE_TO_FLOAT((pixel >> 24) & 0xff);
pRow += 4;
}
src += ps->region->pitch;
p += w0 * 4;
}
break;
case PIPE_FORMAT_S8_Z24:
{
const float scale = 1.0 / (float) 0xffffff;
for (i = 0; i < h; i++) {
float *pRow = p;
for (j = 0; j < w; j++) {
const unsigned pixel = src[j];
pRow[0] =
pRow[1] =
pRow[2] =
pRow[3] = (pixel & 0xffffff) * scale;
pRow += 4;
}
src += ps->region->pitch;
p += w0 * 4;
}
}
break;
default:
assert(0);
}
}
static void
nv40_put_tile_rgba(struct pipe_context *pipe,
struct pipe_surface *ps,
uint x, uint y, uint w, uint h, const float *p)
{
/* TODO */
assert(0);
}
/*
* XXX note: same as code in sp_surface.c
*/
static void
nv40_get_tile(struct pipe_context *pipe,
struct pipe_surface *ps,
uint x, uint y, uint w, uint h,
void *p, int dst_stride)
{
const uint cpp = ps->region->cpp;
const uint w0 = w;
const ubyte *pSrc;
ubyte *pDest;
uint i;
assert(ps->region->map);
CLIP_TILE;
if (dst_stride == 0) {
dst_stride = w0 * cpp;
}
pSrc = ps->region->map + ps->offset + (y * ps->region->pitch + x) * cpp;
pDest = (ubyte *) p;
for (i = 0; i < h; i++) {
memcpy(pDest, pSrc, w0 * cpp);
pDest += dst_stride;
pSrc += ps->region->pitch * cpp;
}
}
/*
* XXX note: same as code in sp_surface.c
*/
static void
nv40_put_tile(struct pipe_context *pipe,
struct pipe_surface *ps,
uint x, uint y, uint w, uint h,
const void *p, int src_stride)
{
const uint cpp = ps->region->cpp;
const uint w0 = w;
const ubyte *pSrc;
ubyte *pDest;
uint i;
assert(ps->region->map);
CLIP_TILE;
if (src_stride == 0) {
src_stride = w0 * cpp;
}
pSrc = (const ubyte *) p;
pDest = ps->region->map + ps->offset + (y * ps->region->pitch + x) * cpp;
for (i = 0; i < h; i++) {
memcpy(pDest, pSrc, w0 * cpp);
pDest += ps->region->pitch * cpp;
pSrc += src_stride;
}
}
/*
* XXX note: same as code in sp_surface.c
*/
static struct pipe_surface *
nv40_get_tex_surface(struct pipe_context *pipe,
struct pipe_mipmap_tree *mt,
unsigned face, unsigned level, unsigned zslice)
{
struct pipe_surface *ps;
unsigned offset; /* in bytes */
offset = mt->level[level].level_offset;
if (mt->target == PIPE_TEXTURE_CUBE) {
offset += mt->level[level].image_offset[face] * mt->cpp;
}
else if (mt->target == PIPE_TEXTURE_3D) {
offset += mt->level[level].image_offset[zslice] * mt->cpp;
}
else {
assert(face == 0);
assert(zslice == 0);
}
ps = pipe->winsys->surface_alloc(pipe->winsys, mt->format);
if (ps) {
assert(ps->format);
assert(ps->refcount);
pipe_region_reference(&ps->region, mt->region);
ps->width = mt->level[level].width;
ps->height = mt->level[level].height;
ps->offset = offset;
}
return ps;
}
void
nv40_init_surface_functions(struct nv40_context *nv40)
{
nv40->pipe.get_tex_surface = nv40_get_tex_surface;
nv40->pipe.get_tile = nv40_get_tile;
nv40->pipe.put_tile = nv40_put_tile;
nv40->pipe.get_tile_rgba = nv40_get_tile_rgba;
nv40->pipe.put_tile_rgba = nv40_put_tile_rgba;
}
+222
View File
@@ -0,0 +1,222 @@
#include "pipe/p_context.h"
#include "pipe/p_state.h"
#include "pipe/p_util.h"
#include "nv40_context.h"
#include "nv40_dma.h"
#include "nv40_state.h"
#include "nvgl_pipe.h"
boolean
nv40_draw_arrays(struct pipe_context *pipe, unsigned mode, unsigned start,
unsigned count)
{
struct nv40_context *nv40 = (struct nv40_context *)pipe;
unsigned nr;
if (nv40->dirty)
nv40_emit_hw_state(nv40);
BEGIN_RING(curie, NV40TCL_BEGIN_END, 1);
OUT_RING (nvgl_primitive(mode));
nr = (count & 0xff);
if (nr) {
BEGIN_RING(curie, NV40TCL_VB_VERTEX_BATCH, 1);
OUT_RING (((nr - 1) << 24) | start);
start += nr;
}
/*XXX: large arrays (nr>2047) will blow up */
nr = count >> 8;
if (nr) {
assert (nr <= 2047);
BEGIN_RING_NI(curie, NV40TCL_VB_VERTEX_BATCH, nr);
while (nr--) {
OUT_RING(((0x100 - 1) << 24) | start);
start += 0x100;
}
}
BEGIN_RING(curie, NV40TCL_BEGIN_END, 1);
OUT_RING (0);
pipe->flush(pipe, PIPE_FLUSH_WAIT);
return TRUE;
}
static INLINE void
nv40_draw_elements_u08(struct nv40_context *nv40, void *ib,
unsigned start, unsigned count)
{
uint8_t *elts = (uint8_t *)ib + start;
int push, i;
if (count & 1) {
BEGIN_RING(curie, NV40TCL_VB_ELEMENT_U32, 1);
OUT_RING (elts[0]);
elts++; count--;
}
while (count) {
push = MIN2(count, 2046);
BEGIN_RING_NI(curie, NV40TCL_VB_ELEMENT_U16, push);
for (i = 0; i < push; i+=2)
OUT_RING((elts[i+1] << 16) | elts[i]);
count -= push;
elts += push;
}
}
static INLINE void
nv40_draw_elements_u16(struct nv40_context *nv40, void *ib,
unsigned start, unsigned count)
{
uint16_t *elts = (uint16_t *)ib + start;
int push, i;
if (count & 1) {
BEGIN_RING(curie, NV40TCL_VB_ELEMENT_U32, 1);
OUT_RING (elts[0]);
elts++; count--;
}
while (count) {
push = MIN2(count, 2046);
BEGIN_RING_NI(curie, NV40TCL_VB_ELEMENT_U16, push);
for (i = 0; i < push; i+=2)
OUT_RING((elts[i+1] << 16) | elts[i]);
count -= push;
elts += push;
}
}
static INLINE void
nv40_draw_elements_u32(struct nv40_context *nv40, void *ib,
unsigned start, unsigned count)
{
uint32_t *elts = (uint32_t *)ib + start;
int push;
while (count) {
push = MIN2(count, 2047);
BEGIN_RING_NI(curie, NV40TCL_VB_ELEMENT_U32, push);
OUT_RINGp (elts, push);
count -= push;
elts += push;
}
}
boolean
nv40_draw_elements(struct pipe_context *pipe,
struct pipe_buffer_handle *indexBuffer, unsigned indexSize,
unsigned mode, unsigned start, unsigned count)
{
struct nv40_context *nv40 = (struct nv40_context *)pipe;
void *ib;
if (nv40->dirty)
nv40_emit_hw_state(nv40);
ib = pipe->winsys->buffer_map(pipe->winsys, indexBuffer,
PIPE_BUFFER_FLAG_READ);
if (!ib) {
NOUVEAU_ERR("Couldn't map index buffer!!\n");
return FALSE;
}
BEGIN_RING(curie, NV40TCL_BEGIN_END, 1);
OUT_RING (nvgl_primitive(mode));
switch (indexSize) {
case 1:
nv40_draw_elements_u08(nv40, ib, start, count);
break;
case 2:
nv40_draw_elements_u16(nv40, ib, start, count);
break;
case 4:
nv40_draw_elements_u32(nv40, ib, start, count);
break;
default:
NOUVEAU_ERR("unsupported elt size %d\n", indexSize);
break;
}
BEGIN_RING(curie, NV40TCL_BEGIN_END, 1);
OUT_RING (0);
pipe->winsys->buffer_unmap(pipe->winsys, ib);
pipe->flush(pipe, PIPE_FLUSH_WAIT);
return TRUE;
}
static INLINE int
nv40_vbo_format_to_ncomp(uint format)
{
switch (format) {
case PIPE_FORMAT_R32G32B32A32_FLOAT: return 4;
case PIPE_FORMAT_R32G32B32_FLOAT: return 3;
case PIPE_FORMAT_R32G32_FLOAT: return 2;
case PIPE_FORMAT_R32_FLOAT: return 1;
default:
NOUVEAU_ERR("AII, unknown vbo format %d\n", format);
return 1;
}
}
void
nv40_vbo_arrays_update(struct nv40_context *nv40)
{
struct nouveau_winsys *nvws = nv40->nvws;
struct nv40_vertex_program *vp = nv40->vertprog.vp;
uint32_t inputs, vtxfmt[16];
int hw, num_hw;
inputs = vp->ir;
for (hw = 0; hw < 16 && inputs; hw++) {
if (inputs & (1 << hw)) {
num_hw = hw;
inputs &= ~(1 << hw);
}
}
num_hw++;
inputs = vp->ir;
BEGIN_RING(curie, NV40TCL_VTXBUF_ADDRESS(0), num_hw);
for (hw = 0; hw < num_hw; hw++) {
struct pipe_vertex_element *ve;
struct pipe_vertex_buffer *vb;
if (!(inputs & (1 << hw))) {
OUT_RING(0);
vtxfmt[hw] = NV40TCL_VTXFMT_TYPE_FLOAT;
continue;
}
ve = &nv40->vtxelt[hw];
vb = &nv40->vtxbuf[ve->vertex_buffer_index];
OUT_RELOC(vb->buffer, vb->buffer_offset + ve->src_offset,
NOUVEAU_BO_GART | NOUVEAU_BO_VRAM | NOUVEAU_BO_LOW |
NOUVEAU_BO_OR | NOUVEAU_BO_RD, 0,
NV40TCL_VTXBUF_ADDRESS_DMA1);
vtxfmt[hw] = ((vb->pitch << NV40TCL_VTXFMT_STRIDE_SHIFT) |
(nv40_vbo_format_to_ncomp(ve->src_format) <<
NV40TCL_VTXFMT_SIZE_SHIFT) |
NV40TCL_VTXFMT_TYPE_FLOAT);
}
BEGIN_RING(curie, 0x1710, 1);
OUT_RING (0); /* vtx cache flush */
BEGIN_RING(curie, NV40TCL_VTXFMT(0), num_hw);
OUT_RINGp (vtxfmt, num_hw);
}
+594
View File
@@ -0,0 +1,594 @@
#include "pipe/p_context.h"
#include "pipe/p_defines.h"
#include "pipe/p_state.h"
#include "pipe/tgsi/exec/tgsi_token.h"
#include "pipe/tgsi/exec/tgsi_parse.h"
#include "nv40_context.h"
#include "nv40_dma.h"
#include "nv40_state.h"
#define SWZ_X 0
#define SWZ_Y 1
#define SWZ_Z 2
#define SWZ_W 3
#define MASK_X 8
#define MASK_Y 4
#define MASK_Z 2
#define MASK_W 1
#define MASK_ALL (MASK_X|MASK_Y|MASK_Z|MASK_W)
#define DEF_SCALE 0
#define DEF_CTEST 0
#include "nv40_shader.h"
#define swz(s,x,y,z,w) nv40_sr_swz((s), SWZ_##x, SWZ_##y, SWZ_##z, SWZ_##w)
#define neg(s) nv40_sr_neg((s))
#define abs(s) nv40_sr_abs((s))
static uint32_t
passthrough_vp_data[] = {
0x40041c6c, 0x0040010d, 0x8106c083, 0x6041ff84,
0x40041c6c, 0x0040000d, 0x8106c083, 0x6041ff81,
};
static struct nv40_vertex_program
passthrough_vp = {
.pipe = NULL,
.translated = TRUE,
.insn = passthrough_vp_data,
.insn_len = sizeof(passthrough_vp_data) / sizeof(uint32_t),
.ir = 0x00000003,
.or = 0x00000001,
};
struct nv40_vpc {
struct nv40_vertex_program *vp;
uint output_map[PIPE_MAX_SHADER_OUTPUTS];
int high_temp;
int temp_temp_count;
};
static INLINE struct nv40_sreg
nv40_sr_temp(struct nv40_vpc *vpc)
{
int idx;
idx = vpc->temp_temp_count++;
idx += vpc->high_temp;
return nv40_sr(0, NV40_VP_SRC_REG_TYPE_TEMP, idx);
}
static INLINE struct nv40_sreg
nv40_sr_const(struct nv40_vpc *vpc, int pipe,
float x, float y, float z, float w)
{
struct nv40_vertex_program *vp = vpc->vp;
int idx = vp->num_consts;
vp->consts[idx].pipe_id = pipe;
vp->consts[idx].hw_id = idx;
vp->consts[idx].value[0] = x;
vp->consts[idx].value[1] = y;
vp->consts[idx].value[2] = z;
vp->consts[idx].value[3] = w;
vp->num_consts++;
return nv40_sr(0, NV40_VP_SRC_REG_TYPE_CONST, idx);
}
#define arith(cc,s,o,d,m,s0,s1,s2) \
nv40_vp_arith((cc), (s), NV40_VP_INST_##o, (d), (m), (s0), (s1), (s2))
#define temp(vpc) nv40_sr_temp((vpc))
#define constant(v,p,x,y,z,w) nv40_sr_const((v), (p), (x), (y), (z), (w))
static void
emit_src(struct nv40_vpc *vpc, uint32_t *hw, int pos, struct nv40_sreg src)
{
struct nv40_vertex_program *vp = vpc->vp;
uint32_t sr = 0;
sr |= (src.type << NV40_VP_SRC_REG_TYPE_SHIFT);
if (src.type == NV40_VP_SRC_REG_TYPE_INPUT) {
vp->ir |= (1 << src.index);
hw[1] |= (src.index << NV40_VP_INST_INPUT_SRC_SHIFT);
} else
if (src.type == NV40_VP_SRC_REG_TYPE_CONST) {
hw[1] |= (src.index << NV40_VP_INST_CONST_SRC_SHIFT);
} else {
sr |= (src.index << NV40_VP_SRC_TEMP_SRC_SHIFT);
}
if (src.negate)
sr |= NV40_VP_SRC_NEGATE;
if (src.abs)
hw[0] |= (1 << (21 + pos));
sr |= ((src.swz[0] << NV40_VP_SRC_SWZ_X_SHIFT) |
(src.swz[1] << NV40_VP_SRC_SWZ_Y_SHIFT) |
(src.swz[2] << NV40_VP_SRC_SWZ_Z_SHIFT) |
(src.swz[3] << NV40_VP_SRC_SWZ_W_SHIFT));
switch (pos) {
case 0:
hw[1] |= ((sr & NV40_VP_SRC0_HIGH_MASK) >>
NV40_VP_SRC0_HIGH_SHIFT) << NV40_VP_INST_SRC0H_SHIFT;
hw[2] |= (sr & NV40_VP_SRC0_LOW_MASK) <<
NV40_VP_INST_SRC0L_SHIFT;
break;
case 1:
hw[2] |= sr << NV40_VP_INST_SRC1_SHIFT;
break;
case 2:
hw[2] |= ((sr & NV40_VP_SRC2_HIGH_MASK) >>
NV40_VP_SRC2_HIGH_SHIFT) << NV40_VP_INST_SRC2H_SHIFT;
hw[3] |= (sr & NV40_VP_SRC2_LOW_MASK) <<
NV40_VP_INST_SRC2L_SHIFT;
break;
default:
assert(0);
}
}
static void
emit_dst(struct nv40_vpc *vpc, uint32_t *hw, int slot, struct nv40_sreg dst)
{
struct nv40_vertex_program *vp = vpc->vp;
if (dst.output == 0) {
hw[3] |= NV40_VP_INST_DEST_MASK;
if (slot == 0) {
hw[0] |= (dst.index <<
NV40_VP_INST_VEC_DEST_TEMP_SHIFT);
} else {
hw[3] |= (dst.index <<
NV40_VP_INST_SCA_DEST_TEMP_SHIFT);
}
} else {
switch (dst.index) {
case NV40_VP_INST_DEST_COL0 : vp->or |= (1 << 0); break;
case NV40_VP_INST_DEST_COL1 : vp->or |= (1 << 1); break;
case NV40_VP_INST_DEST_BFC0 : vp->or |= (1 << 2); break;
case NV40_VP_INST_DEST_BFC1 : vp->or |= (1 << 3); break;
case NV40_VP_INST_DEST_FOGC : vp->or |= (1 << 4); break;
case NV40_VP_INST_DEST_PSZ : vp->or |= (1 << 5); break;
case NV40_VP_INST_DEST_TC(0): vp->or |= (1 << 14); break;
case NV40_VP_INST_DEST_TC(1): vp->or |= (1 << 15); break;
case NV40_VP_INST_DEST_TC(2): vp->or |= (1 << 16); break;
case NV40_VP_INST_DEST_TC(3): vp->or |= (1 << 17); break;
case NV40_VP_INST_DEST_TC(4): vp->or |= (1 << 18); break;
case NV40_VP_INST_DEST_TC(5): vp->or |= (1 << 19); break;
case NV40_VP_INST_DEST_TC(6): vp->or |= (1 << 20); break;
case NV40_VP_INST_DEST_TC(7): vp->or |= (1 << 21); break;
default:
break;
}
hw[3] |= (dst.index << NV40_VP_INST_DEST_SHIFT);
if (slot == 0) {
hw[0] |= NV40_VP_INST_VEC_RESULT;
hw[0] |= NV40_VP_INST_VEC_DEST_TEMP_MASK;
} else {
hw[3] |= NV40_VP_INST_SCA_RESULT;
hw[3] |= NV40_VP_INST_SCA_DEST_TEMP_MASK;
}
}
}
static void
nv40_vp_arith(struct nv40_vpc *vpc, int slot, int op,
struct nv40_sreg dst, int mask,
struct nv40_sreg s0, struct nv40_sreg s1,
struct nv40_sreg s2)
{
struct nv40_vertex_program *vp = vpc->vp;
uint32_t *hw = &vp->insn[vp->insn_len];
hw[0] |= (NV40_VP_INST_COND_TR << NV40_VP_INST_COND_SHIFT);
hw[0] |= ((0 << NV40_VP_INST_COND_SWZ_X_SHIFT) |
(1 << NV40_VP_INST_COND_SWZ_Y_SHIFT) |
(2 << NV40_VP_INST_COND_SWZ_Z_SHIFT) |
(3 << NV40_VP_INST_COND_SWZ_W_SHIFT));
if (slot == 0) {
hw[1] |= (op << NV40_VP_INST_VEC_OPCODE_SHIFT);
hw[3] |= (NV40_VP_INST_SCA_RESULT |
NV40_VP_INST_SCA_DEST_TEMP_MASK);
hw[3] |= (mask << NV40_VP_INST_VEC_WRITEMASK_SHIFT);
} else {
hw[1] |= (op << NV40_VP_INST_SCA_OPCODE_SHIFT);
hw[1] |= (NV40_VP_INST_VEC_DEST_TEMP_MASK | (1 << 20));
hw[3] |= (mask << NV40_VP_INST_SCA_WRITEMASK_SHIFT);
}
emit_dst(vpc, hw, slot, dst);
emit_src(vpc, hw, 0, s0);
emit_src(vpc, hw, 1, s1);
emit_src(vpc, hw, 2, s2);
vp->insn_len += 4;
}
static INLINE struct nv40_sreg
tgsi_src(struct nv40_vpc *vpc, const struct tgsi_full_src_register *fsrc) {
struct nv40_sreg src;
switch (fsrc->SrcRegister.File) {
case TGSI_FILE_INPUT:
src = nv40_sr(0, NV40_VP_SRC_REG_TYPE_INPUT,
fsrc->SrcRegister.Index);
break;
case TGSI_FILE_CONSTANT:
src = constant(vpc, fsrc->SrcRegister.Index, 0, 0, 0, 0);
break;
case TGSI_FILE_TEMPORARY:
if (vpc->high_temp < fsrc->SrcRegister.Index)
vpc->high_temp = fsrc->SrcRegister.Index;
src = nv40_sr(0, NV40_VP_SRC_REG_TYPE_TEMP,
fsrc->SrcRegister.Index);
break;
default:
NOUVEAU_ERR("bad src file\n");
break;
}
src.abs = fsrc->SrcRegisterExtMod.Absolute;
src.negate = fsrc->SrcRegister.Negate;
src.swz[0] = fsrc->SrcRegister.SwizzleX;
src.swz[1] = fsrc->SrcRegister.SwizzleY;
src.swz[2] = fsrc->SrcRegister.SwizzleZ;
src.swz[3] = fsrc->SrcRegister.SwizzleW;
return src;
}
static INLINE struct nv40_sreg
tgsi_dst(struct nv40_vpc *vpc, const struct tgsi_full_dst_register *fdst) {
uint out, idx;
switch (fdst->DstRegister.File) {
case TGSI_FILE_OUTPUT:
out = 1;
idx = vpc->output_map[fdst->DstRegister.Index];
break;
case TGSI_FILE_TEMPORARY:
out = 0;
idx = fdst->DstRegister.Index;
if (vpc->high_temp < idx)
vpc->high_temp = idx;
break;
default:
NOUVEAU_ERR("bad dst file\n");
break;
}
return nv40_sr(out, NV40_VP_SRC_REG_TYPE_TEMP, idx);
}
static INLINE int
tgsi_mask(uint tgsi)
{
int mask = 0;
if (tgsi & TGSI_WRITEMASK_X) mask |= MASK_X;
if (tgsi & TGSI_WRITEMASK_Y) mask |= MASK_Y;
if (tgsi & TGSI_WRITEMASK_Z) mask |= MASK_Z;
if (tgsi & TGSI_WRITEMASK_W) mask |= MASK_W;
return mask;
}
static boolean
nv40_vertprog_parse_instruction(struct nv40_vpc *vpc,
const struct tgsi_full_instruction *finst)
{
struct nv40_sreg src[3], dst, tmp;
struct nv40_sreg none = nv40_sr(0, NV40_VP_SRC_REG_TYPE_INPUT, 0);
int mask;
int ai = -1, ci = -1;
int i;
if (finst->Instruction.Opcode == TGSI_OPCODE_RET)
return TRUE;
vpc->temp_temp_count = 0;
for (i = 0; i < finst->Instruction.NumSrcRegs; i++) {
const struct tgsi_full_src_register *fsrc;
fsrc = &finst->FullSrcRegisters[i];
if (fsrc->SrcRegister.File == TGSI_FILE_TEMPORARY) {
src[i] = tgsi_src(vpc, fsrc);
}
}
for (i = 0; i < finst->Instruction.NumSrcRegs; i++) {
const struct tgsi_full_src_register *fsrc;
fsrc = &finst->FullSrcRegisters[i];
switch (fsrc->SrcRegister.File) {
case TGSI_FILE_INPUT:
if (ai == -1 || ai == fsrc->SrcRegister.Index) {
ai = fsrc->SrcRegister.Index;
src[i] = tgsi_src(vpc, fsrc);
} else {
NOUVEAU_MSG("extra src attr %d\n",
fsrc->SrcRegister.Index);
src[i] = temp(vpc);
arith(vpc, 0, OP_MOV, src[i], MASK_ALL,
tgsi_src(vpc, fsrc), none, none);
}
break;
case TGSI_FILE_CONSTANT:
if (ci == -1 || ci == fsrc->SrcRegister.Index) {
ci = fsrc->SrcRegister.Index;
src[i] = tgsi_src(vpc, fsrc);
} else {
src[i] = temp(vpc);
arith(vpc, 0, OP_MOV, src[i], MASK_ALL,
tgsi_src(vpc, fsrc), none, none);
}
break;
case TGSI_FILE_TEMPORARY:
/* handled above */
break;
default:
NOUVEAU_ERR("bad src file\n");
return FALSE;
}
}
dst = tgsi_dst(vpc, &finst->FullDstRegisters[0]);
mask = tgsi_mask(finst->FullDstRegisters[0].DstRegister.WriteMask);
switch (finst->Instruction.Opcode) {
case TGSI_OPCODE_ABS:
arith(vpc, 0, OP_MOV, dst, mask, abs(src[0]), none, none);
break;
case TGSI_OPCODE_ADD:
arith(vpc, 0, OP_ADD, dst, mask, src[0], none, src[1]);
break;
case TGSI_OPCODE_ARL:
arith(vpc, 0, OP_ARL, dst, mask, src[0], none, none);
break;
case TGSI_OPCODE_DP3:
arith(vpc, 0, OP_DP3, dst, mask, src[0], src[1], none);
break;
case TGSI_OPCODE_DP4:
arith(vpc, 0, OP_DP4, dst, mask, src[0], src[1], none);
break;
case TGSI_OPCODE_DPH:
arith(vpc, 0, OP_DPH, dst, mask, src[0], src[1], none);
break;
case TGSI_OPCODE_DST:
arith(vpc, 0, OP_DST, dst, mask, src[0], src[1], none);
break;
case TGSI_OPCODE_EX2:
arith(vpc, 1, OP_EX2, dst, mask, none, none, src[0]);
break;
case TGSI_OPCODE_EXP:
arith(vpc, 1, OP_EXP, dst, mask, none, none, src[0]);
break;
case TGSI_OPCODE_FLR:
arith(vpc, 0, OP_FLR, dst, mask, src[0], none, none);
break;
case TGSI_OPCODE_FRC:
arith(vpc, 0, OP_FRC, dst, mask, src[0], none, none);
break;
case TGSI_OPCODE_LG2:
arith(vpc, 1, OP_LG2, dst, mask, none, none, src[0]);
break;
case TGSI_OPCODE_LIT:
arith(vpc, 1, OP_LIT, dst, mask, none, none, src[0]);
break;
case TGSI_OPCODE_LOG:
arith(vpc, 1, OP_LOG, dst, mask, none, none, src[0]);
break;
case TGSI_OPCODE_MAD:
arith(vpc, 0, OP_MAD, dst, mask, src[0], src[1], src[2]);
break;
case TGSI_OPCODE_MAX:
arith(vpc, 0, OP_MAX, dst, mask, src[0], src[1], none);
break;
case TGSI_OPCODE_MIN:
arith(vpc, 0, OP_MIN, dst, mask, src[0], src[1], none);
break;
case TGSI_OPCODE_MOV:
arith(vpc, 0, OP_MOV, dst, mask, src[0], none, none);
break;
case TGSI_OPCODE_MUL:
arith(vpc, 0, OP_MUL, dst, mask, src[0], src[1], none);
break;
case TGSI_OPCODE_POW:
tmp = temp(vpc);
arith(vpc, 1, OP_LG2, tmp, MASK_X, none, none,
swz(src[0], X, X, X, X));
arith(vpc, 0, OP_MUL, tmp, MASK_X, swz(tmp, X, X, X, X),
swz(src[1], X, X, X, X), none);
arith(vpc, 1, OP_EX2, dst, mask, none, none,
swz(tmp, X, X, X, X));
break;
case TGSI_OPCODE_RCP:
arith(vpc, 1, OP_RCP, dst, mask, none, none, src[0]);
break;
case TGSI_OPCODE_RSQ:
arith(vpc, 1, OP_RSQ, dst, mask, none, none, src[0]);
break;
case TGSI_OPCODE_SGE:
arith(vpc, 0, OP_SGE, dst, mask, src[0], src[1], none);
break;
case TGSI_OPCODE_SLT:
arith(vpc, 0, OP_SLT, dst, mask, src[0], src[1], none);
break;
case TGSI_OPCODE_SUB:
arith(vpc, 0, OP_ADD, dst, mask, src[0], none, neg(src[1]));
break;
case TGSI_OPCODE_XPD:
tmp = temp(vpc);
arith(vpc, 0, OP_MUL, tmp, mask,
swz(src[0], Z, X, Y, Y), swz(src[1], Y, Z, X, X), none);
arith(vpc, 0, OP_MAD, dst, (mask & ~MASK_W),
swz(src[0], Y, Z, X, X), swz(src[1], Z, X, Y, Y),
neg(tmp));
break;
default:
NOUVEAU_ERR("invalid opcode %d\n", finst->Instruction.Opcode);
return FALSE;
}
return TRUE;
}
static boolean
nv40_vertprog_parse_decl_output(struct nv40_vpc *vpc,
const struct tgsi_full_declaration *fdec)
{
int hw;
switch (fdec->Semantic.SemanticName) {
case TGSI_SEMANTIC_POSITION:
hw = NV40_VP_INST_DEST_POS;
break;
case TGSI_SEMANTIC_COLOR:
if (fdec->Semantic.SemanticIndex == 0) {
hw = NV40_VP_INST_DEST_COL0;
} else
if (fdec->Semantic.SemanticIndex == 1) {
hw = NV40_VP_INST_DEST_COL1;
} else {
NOUVEAU_ERR("bad colour semantic index\n");
return FALSE;
}
break;
case TGSI_SEMANTIC_BCOLOR:
if (fdec->Semantic.SemanticIndex == 0) {
hw = NV40_VP_INST_DEST_BFC0;
} else
if (fdec->Semantic.SemanticIndex == 1) {
hw = NV40_VP_INST_DEST_BFC1;
} else {
NOUVEAU_ERR("bad bcolour semantic index\n");
return FALSE;
}
break;
case TGSI_SEMANTIC_FOG:
hw = NV40_VP_INST_DEST_FOGC;
break;
case TGSI_SEMANTIC_PSIZE:
hw = NV40_VP_INST_DEST_PSZ;
break;
case TGSI_SEMANTIC_GENERIC:
if (fdec->Semantic.SemanticIndex <= 7) {
hw = NV40_VP_INST_DEST_TC(fdec->Semantic.SemanticIndex);
} else {
NOUVEAU_ERR("bad generic semantic index\n");
return FALSE;
}
break;
default:
NOUVEAU_ERR("bad output semantic\n");
return FALSE;
}
vpc->output_map[fdec->u.DeclarationRange.First] = hw;
return TRUE;
}
void
nv40_vertprog_translate(struct nv40_context *nv40,
struct nv40_vertex_program *vp)
{
struct tgsi_parse_context parse;
struct nv40_vpc *vpc = NULL;
vpc = calloc(1, sizeof(struct nv40_vpc));
if (!vpc)
return;
vp->insn = calloc(1, 128*4*sizeof(uint32_t));
vpc->vp = vp;
vpc->high_temp = -1;
tgsi_parse_init(&parse, vp->pipe->tokens);
while (!tgsi_parse_end_of_tokens(&parse)) {
tgsi_parse_token(&parse);
switch (parse.FullToken.Token.Type) {
case TGSI_TOKEN_TYPE_DECLARATION:
{
const struct tgsi_full_declaration *fdec;
fdec = &parse.FullToken.FullDeclaration;
switch (fdec->Declaration.File) {
case TGSI_FILE_OUTPUT:
if (!nv40_vertprog_parse_decl_output(vpc, fdec))
goto out_err;
break;
default:
break;
}
}
break;
case TGSI_TOKEN_TYPE_IMMEDIATE:
break;
case TGSI_TOKEN_TYPE_INSTRUCTION:
{
const struct tgsi_full_instruction *finst;
finst = &parse.FullToken.FullInstruction;
if (!nv40_vertprog_parse_instruction(vpc, finst))
goto out_err;
}
break;
default:
break;
}
}
vp->insn[vp->insn_len - 1] |= NV40_VP_INST_LAST;
#if 0
{
int i;
for (i = 0; i < vp->insn_len; i++)
NOUVEAU_ERR("inst[%d] = 0x%08x\n", i, vp->insn[i]);
}
#endif
vp->translated = TRUE;
out_err:
tgsi_parse_free(&parse);
free(vpc);
}
void
nv40_vertprog_bind(struct nv40_context *nv40, struct nv40_vertex_program *vp)
{
int i;
if (!vp->translated) {
NOUVEAU_ERR("vtxprog invalid, using passthrough shader\n");
vp = &passthrough_vp;
}
if (!vp->on_hw) {
if (nv40->vertprog.active_vp)
nv40->vertprog.active_vp->on_hw = FALSE;
vp->on_hw = TRUE;
vp->start_ip = 0;
BEGIN_RING(curie, NV40TCL_VP_UPLOAD_FROM_ID, 1);
OUT_RING (vp->start_ip);
for (i = 0; i < vp->insn_len; i += 4) {
BEGIN_RING(curie, NV40TCL_VP_UPLOAD_INST(0), 4);
OUT_RINGp (&vp->insn[i], 4);
}
}
BEGIN_RING(curie, NV40TCL_VP_START_FROM_ID, 1);
OUT_RING (vp->start_ip);
BEGIN_RING(curie, NV40TCL_VP_ATTRIB_EN, 2);
OUT_RING (vp->ir);
OUT_RING (vp->or);
nv40->vertprog.active_vp = vp;
}
+198
View File
@@ -0,0 +1,198 @@
#ifndef __NVGL_PIPE_H__
#define __NVGL_PIPE_H__
#include <GL/gl.h>
static INLINE unsigned
nvgl_blend_func(unsigned factor)
{
switch (factor) {
case PIPE_BLENDFACTOR_ONE:
return GL_ONE;
case PIPE_BLENDFACTOR_SRC_COLOR:
return GL_SRC_COLOR;
case PIPE_BLENDFACTOR_SRC_ALPHA:
return GL_SRC_ALPHA;
case PIPE_BLENDFACTOR_DST_ALPHA:
return GL_DST_ALPHA;
case PIPE_BLENDFACTOR_DST_COLOR:
return GL_DST_COLOR;
case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE:
return GL_SRC_ALPHA_SATURATE;
case PIPE_BLENDFACTOR_CONST_COLOR:
return GL_CONSTANT_COLOR;
case PIPE_BLENDFACTOR_CONST_ALPHA:
return GL_CONSTANT_ALPHA;
case PIPE_BLENDFACTOR_ZERO:
return GL_ZERO;
case PIPE_BLENDFACTOR_INV_SRC_COLOR:
return GL_ONE_MINUS_SRC_COLOR;
case PIPE_BLENDFACTOR_INV_SRC_ALPHA:
return GL_ONE_MINUS_SRC_ALPHA;
case PIPE_BLENDFACTOR_INV_DST_ALPHA:
return GL_ONE_MINUS_DST_ALPHA;
case PIPE_BLENDFACTOR_INV_DST_COLOR:
return GL_ONE_MINUS_DST_COLOR;
case PIPE_BLENDFACTOR_INV_CONST_COLOR:
return GL_ONE_MINUS_CONSTANT_COLOR;
case PIPE_BLENDFACTOR_INV_CONST_ALPHA:
return GL_ONE_MINUS_CONSTANT_ALPHA;
default:
return GL_ONE;
}
}
static INLINE unsigned
nvgl_blend_eqn(unsigned func)
{
switch (func) {
case PIPE_BLEND_ADD:
return GL_FUNC_ADD;
case PIPE_BLEND_SUBTRACT:
return GL_FUNC_SUBTRACT;
case PIPE_BLEND_REVERSE_SUBTRACT:
return GL_FUNC_REVERSE_SUBTRACT;
case PIPE_BLEND_MIN:
return GL_MIN;
case PIPE_BLEND_MAX:
return GL_MAX;
default:
return GL_FUNC_ADD;
}
}
static INLINE unsigned
nvgl_logicop_func(unsigned func)
{
switch (func) {
case PIPE_LOGICOP_CLEAR:
return GL_CLEAR;
case PIPE_LOGICOP_NOR:
return GL_NOR;
case PIPE_LOGICOP_AND_INVERTED:
return GL_AND_INVERTED;
case PIPE_LOGICOP_COPY_INVERTED:
return GL_COPY_INVERTED;
case PIPE_LOGICOP_AND_REVERSE:
return GL_AND_REVERSE;
case PIPE_LOGICOP_INVERT:
return GL_INVERT;
case PIPE_LOGICOP_XOR:
return GL_XOR;
case PIPE_LOGICOP_NAND:
return GL_NAND;
case PIPE_LOGICOP_AND:
return GL_AND;
case PIPE_LOGICOP_EQUIV:
return GL_EQUIV;
case PIPE_LOGICOP_NOOP:
return GL_NOOP;
case PIPE_LOGICOP_OR_INVERTED:
return GL_OR_INVERTED;
case PIPE_LOGICOP_COPY:
return GL_COPY;
case PIPE_LOGICOP_OR_REVERSE:
return GL_OR_REVERSE;
case PIPE_LOGICOP_OR:
return GL_OR;
case PIPE_LOGICOP_SET:
return GL_SET;
default:
return GL_CLEAR;
}
}
static INLINE unsigned
nvgl_comparison_op(unsigned op)
{
switch (op) {
case PIPE_FUNC_NEVER:
return GL_NEVER;
case PIPE_FUNC_LESS:
return GL_LESS;
case PIPE_FUNC_EQUAL:
return GL_EQUAL;
case PIPE_FUNC_LEQUAL:
return GL_LEQUAL;
case PIPE_FUNC_GREATER:
return GL_GREATER;
case PIPE_FUNC_NOTEQUAL:
return GL_NOTEQUAL;
case PIPE_FUNC_GEQUAL:
return GL_GEQUAL;
case PIPE_FUNC_ALWAYS:
return GL_ALWAYS;
default:
return GL_NEVER;
}
}
static INLINE unsigned
nvgl_polygon_mode(unsigned mode)
{
switch (mode) {
case PIPE_POLYGON_MODE_FILL:
return GL_FILL;
case PIPE_POLYGON_MODE_LINE:
return GL_LINE;
case PIPE_POLYGON_MODE_POINT:
return GL_POINT;
default:
return GL_FILL;
}
}
static INLINE unsigned
nvgl_stencil_op(unsigned op)
{
switch (op) {
case PIPE_STENCIL_OP_KEEP:
return GL_KEEP;
case PIPE_STENCIL_OP_ZERO:
return GL_ZERO;
case PIPE_STENCIL_OP_REPLACE:
return GL_REPLACE;
case PIPE_STENCIL_OP_INCR:
return GL_INCR;
case PIPE_STENCIL_OP_DECR:
return GL_DECR;
case PIPE_STENCIL_OP_INCR_WRAP:
return GL_INCR_WRAP;
case PIPE_STENCIL_OP_DECR_WRAP:
return GL_DECR_WRAP;
case PIPE_STENCIL_OP_INVERT:
return GL_INVERT;
default:
return GL_KEEP;
}
}
static INLINE unsigned
nvgl_primitive(unsigned prim) {
switch (prim) {
case PIPE_PRIM_POINTS:
return GL_POINTS + 1;
case PIPE_PRIM_LINES:
return GL_LINES + 1;
case PIPE_PRIM_LINE_LOOP:
return GL_LINE_LOOP + 1;
case PIPE_PRIM_LINE_STRIP:
return GL_LINE_STRIP + 1;
case PIPE_PRIM_TRIANGLES:
return GL_TRIANGLES + 1;
case PIPE_PRIM_TRIANGLE_STRIP:
return GL_TRIANGLE_STRIP + 1;
case PIPE_PRIM_TRIANGLE_FAN:
return GL_TRIANGLE_FAN + 1;
case PIPE_PRIM_QUADS:
return GL_QUADS + 1;
case PIPE_PRIM_QUAD_STRIP:
return GL_QUAD_STRIP + 1;
case PIPE_PRIM_POLYGON:
return GL_POLYGON + 1;
default:
return GL_POINTS + 1;
}
}
#endif