diff options
Diffstat (limited to 'src/mesa/drivers')
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, + ¬ifier->drm, + sizeof(notifier->drm)))) { + nouveau_notifier_free((void *)¬ifier); + return ret; + } + + notifier->map = (void *)nouveau_channel(userchan)->notifier_block + + notifier->drm.offset; + *usernotifier = ¬ifier->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, ®ion->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; +} + |