summaryrefslogtreecommitdiff
path: root/src/mesa/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesa/drivers')
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/Makefile38
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_bo.c347
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_channel.c130
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_context.c228
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_context.h105
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_device.c144
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_device.h29
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_dma.c193
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_dma.h158
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_dri.h28
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_drmif.h212
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_grobj.c107
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_local.h82
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_lock.c103
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_notifier.c140
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_screen.c253
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_screen.h17
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_swapbuffers.c98
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_swapbuffers.h10
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_winsys.c90
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_winsys_pipe.c251
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_winsys_pipe.h23
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_winsys_softpipe.c82
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nv04_region.c239
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nv50_region.c51
25 files changed, 3158 insertions, 0 deletions
diff --git a/src/mesa/drivers/dri/nouveau_winsys/Makefile b/src/mesa/drivers/dri/nouveau_winsys/Makefile
new file mode 100644
index 0000000000..97b861526f
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/Makefile
@@ -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:
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_bo.c b/src/mesa/drivers/dri/nouveau_winsys/nouveau_bo.c
new file mode 100644
index 0000000000..3b508cf92b
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_bo.c
@@ -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;
+}
+
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_channel.c b/src/mesa/drivers/dri/nouveau_winsys/nouveau_channel.c
new file mode 100644
index 0000000000..ef41020b72
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_channel.c
@@ -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);
+ }
+}
+
+
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_context.c b/src/mesa/drivers/dri/nouveau_winsys/nouveau_context.c
new file mode 100644
index 0000000000..584d236f34
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_context.c
@@ -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;
+}
+
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_context.h b/src/mesa/drivers/dri/nouveau_winsys/nouveau_context.h
new file mode 100644
index 0000000000..f2557af935
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_context.h
@@ -0,0 +1,105 @@
+#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;
+ struct nouveau_grobj *NvM2MF;
+ 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
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_device.c b/src/mesa/drivers/dri/nouveau_winsys/nouveau_device.c
new file mode 100644
index 0000000000..a3f5513550
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_device.c
@@ -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;
+}
+
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_device.h b/src/mesa/drivers/dri/nouveau_winsys/nouveau_device.h
new file mode 100644
index 0000000000..744a89f74b
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_device.h
@@ -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
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_dma.c b/src/mesa/drivers/dri/nouveau_winsys/nouveau_dma.c
new file mode 100644
index 0000000000..6e123c4473
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_dma.c
@@ -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;
+}
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_dma.h b/src/mesa/drivers/dri/nouveau_winsys/nouveau_dma.h
new file mode 100644
index 0000000000..927841c4eb
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_dma.h
@@ -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
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_dri.h b/src/mesa/drivers/dri/nouveau_winsys/nouveau_dri.h
new file mode 100644
index 0000000000..1207c2d609
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_dri.h
@@ -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
+
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_drmif.h b/src/mesa/drivers/dri/nouveau_winsys/nouveau_drmif.h
new file mode 100644
index 0000000000..1a21da6985
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_drmif.h
@@ -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
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_grobj.c b/src/mesa/drivers/dri/nouveau_winsys/nouveau_grobj.c
new file mode 100644
index 0000000000..8dab202395
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_grobj.c
@@ -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);
+ }
+}
+
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_local.h b/src/mesa/drivers/dri/nouveau_winsys/nouveau_local.h
new file mode 100644
index 0000000000..4ada5d014b
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_local.h
@@ -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
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_lock.c b/src/mesa/drivers/dri/nouveau_winsys/nouveau_lock.c
new file mode 100644
index 0000000000..ffe7d01d66
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_lock.c
@@ -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);
+}
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_notifier.c b/src/mesa/drivers/dri/nouveau_winsys/nouveau_notifier.c
new file mode 100644
index 0000000000..e423d59b1d
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_notifier.c
@@ -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;
+}
+
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_screen.c b/src/mesa/drivers/dri/nouveau_winsys/nouveau_screen.c
new file mode 100644
index 0000000000..16c4324164
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_screen.c
@@ -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, 24 };
+ u_int8_t stencil_bits_array[4] = { 0, 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;
+}
+
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_screen.h b/src/mesa/drivers/dri/nouveau_winsys/nouveau_screen.h
new file mode 100644
index 0000000000..e53cd873a7
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_screen.h
@@ -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
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_swapbuffers.c b/src/mesa/drivers/dri/nouveau_winsys/nouveau_swapbuffers.c
new file mode 100644
index 0000000000..57598f9cab
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_swapbuffers.c
@@ -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);
+ }
+}
+
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_swapbuffers.h b/src/mesa/drivers/dri/nouveau_winsys/nouveau_swapbuffers.h
new file mode 100644
index 0000000000..825d3da6da
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_swapbuffers.h
@@ -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
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_winsys.c b/src/mesa/drivers/dri/nouveau_winsys/nouveau_winsys.c
new file mode 100644
index 0000000000..a2e85a0aa7
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_winsys.c
@@ -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);
+}
+
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_winsys_pipe.c b/src/mesa/drivers/dri/nouveau_winsys/nouveau_winsys_pipe.c
new file mode 100644
index 0000000000..0dd2cec2ca
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_winsys_pipe.c
@@ -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;
+}
+
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_winsys_pipe.h b/src/mesa/drivers/dri/nouveau_winsys/nouveau_winsys_pipe.h
new file mode 100644
index 0000000000..bcac60851c
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_winsys_pipe.h
@@ -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
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_winsys_softpipe.c b/src/mesa/drivers/dri/nouveau_winsys/nouveau_winsys_softpipe.c
new file mode 100644
index 0000000000..c86575f187
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_winsys_softpipe.c
@@ -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);
+}
+
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nv04_region.c b/src/mesa/drivers/dri/nouveau_winsys/nv04_region.c
new file mode 100644
index 0000000000..1160a8f340
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nv04_region.c
@@ -0,0 +1,239 @@
+#include "pipe/p_context.h"
+
+#include "nouveau_context.h"
+
+static INLINE int
+nv04_surface_format(int cpp)
+{
+ switch (cpp) {
+ case 1: return NV04_CONTEXT_SURFACES_2D_FORMAT_Y8;
+ case 2: return NV04_CONTEXT_SURFACES_2D_FORMAT_R5G6B5;
+ case 4: return NV04_CONTEXT_SURFACES_2D_FORMAT_Y32;
+ default:
+ return -1;
+ }
+}
+
+static INLINE int
+nv04_rect_format(int cpp)
+{
+ switch (cpp) {
+ case 1: return NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT_A8R8G8B8;
+ case 2: return NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT_A16R5G6B5;
+ case 4: return NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT_A8R8G8B8;
+ default:
+ return -1;
+ }
+}
+
+static int
+nv04_region_display(void)
+{
+ NOUVEAU_ERR("unimplemented\n");
+ return 0;
+}
+
+static int
+nv04_region_copy_m2mf(struct nouveau_context *nv, struct pipe_region *dst,
+ unsigned dst_offset, struct pipe_region *src,
+ unsigned src_offset, unsigned line_len, unsigned height)
+{
+ BEGIN_RING(NvM2MF, NV_MEMORY_TO_MEMORY_FORMAT_DMA_BUFFER_IN, 2);
+ OUT_RELOCo(src->buffer, NOUVEAU_BO_GART | NOUVEAU_BO_VRAM |
+ NOUVEAU_BO_RD);
+ OUT_RELOCo(dst->buffer, NOUVEAU_BO_GART | NOUVEAU_BO_VRAM |
+ NOUVEAU_BO_WR);
+
+ while (height) {
+ int count = (height > 2047) ? 2047 : height;
+
+ BEGIN_RING(NvM2MF, NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
+ OUT_RELOCl(src->buffer, src_offset, NOUVEAU_BO_VRAM |
+ NOUVEAU_BO_GART | NOUVEAU_BO_RD);
+ OUT_RELOCl(dst->buffer, dst_offset, NOUVEAU_BO_VRAM |
+ NOUVEAU_BO_GART | NOUVEAU_BO_WR);
+ OUT_RING (src->pitch * src->cpp);
+ OUT_RING (dst->pitch * dst->cpp);
+ OUT_RING (line_len);
+ OUT_RING (count);
+ OUT_RING (0x0101);
+ OUT_RING (0);
+
+ height -= count;
+ src_offset += src->pitch * count;
+ dst_offset += dst->pitch * count;
+ }
+
+ 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;
+
+ /* NV_CONTEXT_SURFACES_2D has buffer alignment restrictions, fallback
+ * to NV_MEMORY_TO_MEMORY_FORMAT in this case.
+ */
+ if ((src_offset & 63) || (dst_offset & 63)) {
+ dst_offset += (dy * dst->pitch + dx) * dst->cpp;
+ src_offset += (sy * src->pitch + sx) * src->cpp;
+ return nv04_region_copy_m2mf(nv, dst, dst_offset, src,
+ src_offset, w * src->cpp, h);
+
+ }
+
+ if ((format = nv04_surface_format(dst->cpp)) < 0) {
+ NOUVEAU_ERR("Bad cpp = %d\n", dst->cpp);
+ return 1;
+ }
+
+ BEGIN_RING(NvCtxSurf2D, NV04_CONTEXT_SURFACES_2D_DMA_IMAGE_SOURCE, 2);
+ OUT_RELOCo(src->buffer, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
+ OUT_RELOCo(dst->buffer, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
+ BEGIN_RING(NvCtxSurf2D, NV04_CONTEXT_SURFACES_2D_FORMAT, 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);
+
+ nouveau_notifier_reset(nv->sync_notifier, 0);
+ BEGIN_RING(NvGdiRect, 0x104, 1);
+ OUT_RING (0);
+ BEGIN_RING(NvGdiRect, 0x100, 1);
+ OUT_RING (0);
+ FIRE_RING();
+ nouveau_notifier_wait_status(nv->sync_notifier, 0, 0, 2000);
+
+ 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, NV04_CONTEXT_SURFACES_2D_DMA_IMAGE_SOURCE, 2);
+ OUT_RELOCo(dst->buffer, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
+ OUT_RELOCo(dst->buffer, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
+ BEGIN_RING(NvCtxSurf2D, NV04_CONTEXT_SURFACES_2D_FORMAT, 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, NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT, 1);
+ OUT_RING (gdirect_format);
+ BEGIN_RING(NvGdiRect, NV04_GDI_RECTANGLE_TEXT_COLOR1_A, 1);
+ OUT_RING (value);
+ BEGIN_RING(NvGdiRect,
+ NV04_GDI_RECTANGLE_TEXT_UNCLIPPED_RECTANGLE_POINT(0), 2);
+ OUT_RING ((dx << 16) | dy);
+ OUT_RING (( w << 16) | h);
+
+ nouveau_notifier_reset(nv->sync_notifier, 0);
+ BEGIN_RING(NvGdiRect, 0x104, 1);
+ OUT_RING (0);
+ BEGIN_RING(NvGdiRect, 0x100, 1);
+ OUT_RING (0);
+ FIRE_RING();
+ nouveau_notifier_wait_status(nv->sync_notifier, 0, 0, 2000);
+
+ 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)
+{
+ unsigned class;
+ int ret;
+
+ if ((ret = nouveau_grobj_alloc(nv->channel, nv->next_handle++, 0x39,
+ &nv->NvM2MF))) {
+ NOUVEAU_ERR("Error creating m2mf object: %d\n", ret);
+ return 1;
+ }
+ BEGIN_RING(NvM2MF, NV_MEMORY_TO_MEMORY_FORMAT_DMA_NOTIFY, 1);
+ OUT_RING (nv->sync_notifier->handle);
+
+ class = nv->chipset < 0x10 ? NV04_CONTEXT_SURFACES_2D :
+ NV10_CONTEXT_SURFACES_2D;
+ if ((ret = nouveau_grobj_alloc(nv->channel, nv->next_handle++, class,
+ &nv->NvCtxSurf2D))) {
+ NOUVEAU_ERR("Error creating 2D surface object: %d\n", ret);
+ return 1;
+ }
+ BEGIN_RING(NvCtxSurf2D, NV04_CONTEXT_SURFACES_2D_DMA_IMAGE_SOURCE, 2);
+ OUT_RING (nv->channel->vram->handle);
+ OUT_RING (nv->channel->vram->handle);
+
+ class = nv->chipset < 0x10 ? NV_IMAGE_BLIT :
+ NV12_IMAGE_BLIT;
+ if ((ret = nouveau_grobj_alloc(nv->channel, nv->next_handle++, class,
+ &nv->NvImageBlit))) {
+ NOUVEAU_ERR("Error creating blit object: %d\n", ret);
+ return 1;
+ }
+ BEGIN_RING(NvImageBlit, NV_IMAGE_BLIT_DMA_NOTIFY, 1);
+ OUT_RING (nv->sync_notifier->handle);
+ BEGIN_RING(NvImageBlit, NV_IMAGE_BLIT_SURFACE, 1);
+ OUT_RING (nv->NvCtxSurf2D->handle);
+ BEGIN_RING(NvImageBlit, NV_IMAGE_BLIT_OPERATION, 1);
+ OUT_RING (NV_IMAGE_BLIT_OPERATION_SRCCOPY);
+
+ class = NV04_GDI_RECTANGLE_TEXT;
+ if ((ret = nouveau_grobj_alloc(nv->channel, nv->next_handle++, class,
+ &nv->NvGdiRect))) {
+ NOUVEAU_ERR("Error creating rect object: %d\n", ret);
+ return 1;
+ }
+ BEGIN_RING(NvGdiRect, NV04_GDI_RECTANGLE_TEXT_DMA_NOTIFY, 1);
+ OUT_RING (nv->sync_notifier->handle);
+ BEGIN_RING(NvGdiRect, NV04_GDI_RECTANGLE_TEXT_SURFACE, 1);
+ OUT_RING (nv->NvCtxSurf2D->handle);
+ BEGIN_RING(NvGdiRect, NV04_GDI_RECTANGLE_TEXT_OPERATION, 1);
+ OUT_RING (NV04_GDI_RECTANGLE_TEXT_OPERATION_SRCCOPY);
+ BEGIN_RING(NvGdiRect, NV04_GDI_RECTANGLE_TEXT_MONOCHROME_FORMAT, 1);
+ OUT_RING (NV04_GDI_RECTANGLE_TEXT_MONOCHROME_FORMAT_LE);
+
+ 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;
+}
+
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nv50_region.c b/src/mesa/drivers/dri/nouveau_winsys/nv50_region.c
new file mode 100644
index 0000000000..c7450c5c8d
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nv50_region.c
@@ -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;
+}
+