Commit 961cbcb6 authored by Keith Whitwell's avatar Keith Whitwell

nouveau: convert nvfx and nv50 to pipe_resources

Compile tested only.

This was a deeper change than I was hoping for, due to the
layering of the pipe_texture implementation in each driver on
top of a shared pipe_buffer implementation in the shared code.

Have modified the shared code to act as a set of convenience
routines operating on nouveau_bo objects.

Each driver now uses the u_resource_vtbl technique to split the
implementation of pipe_resources between the existing miptree code
for textures and a new, minimal buffer implementation in each
driver.

Eventually these should be combined, not least because APIs are now
allowing things like binding buffer resources as textures and render
targets.
parent 18ba7401
......@@ -98,7 +98,7 @@ EGL_DRIVERS_DIRS = glx
# Gallium directories and
GALLIUM_DIRS = auxiliary drivers state_trackers
GALLIUM_AUXILIARIES = $(TOP)/src/gallium/auxiliary/libgallium.a
GALLIUM_DRIVERS_DIRS = softpipe trace identity i915 i965 svga r300
GALLIUM_DRIVERS_DIRS = softpipe trace identity i915 i965 svga r300 nvfx nv50
GALLIUM_DRIVERS = $(foreach DIR,$(GALLIUM_DRIVERS_DIRS),$(TOP)/src/gallium/drivers/$(DIR)/lib$(DIR).a)
GALLIUM_WINSYS_DIRS = null xlib drm
GALLIUM_TARGET_DIRS = libgl-xlib
......
......@@ -5,5 +5,5 @@ include $(TOP)/configs/linux
CONFIG_NAME = linux-debug
OPT_FLAGS = -g
CFLAGS += -pedantic
#CFLAGS += -pedantic
DEFINES += -DDEBUG -DDEBUG_MATH
......@@ -3,7 +3,9 @@ include $(TOP)/configs/current
LIBNAME = nouveau
C_SOURCES = nouveau_screen.c \
nouveau_context.c
LIBRARY_INCLUDES = \
-I$(TOP)/src/gallium/drivers/nouveau/include
C_SOURCES = nouveau_screen.c
include ../../Makefile.template
#include "pipe/p_defines.h"
#include "pipe/p_context.h"
#include "nouveau/nouveau_screen.h"
#include "nouveau/nouveau_context.h"
#include "nouveau/nouveau_bo.h"
static unsigned int
nouveau_reference_flags(struct nouveau_bo *bo)
{
uint32_t bo_flags;
int flags = 0;
bo_flags = nouveau_bo_pending(bo);
if (bo_flags & NOUVEAU_BO_RD)
flags |= PIPE_REFERENCED_FOR_READ;
if (bo_flags & NOUVEAU_BO_WR)
flags |= PIPE_REFERENCED_FOR_WRITE;
return flags;
}
unsigned int
nouveau_is_texture_referenced(struct pipe_context *pipe,
struct pipe_texture *pt,
unsigned face, unsigned level)
{
struct nouveau_miptree *mt = nouveau_miptree(pt);
return nouveau_reference_flags(mt->bo);
}
unsigned int
nouveau_is_buffer_referenced(struct pipe_context *pipe, struct pipe_buffer *pb)
{
struct nouveau_bo *bo = nouveau_bo(pb);
return nouveau_reference_flags(bo);
}
#ifndef __NOUVEAU_CONTEXT_H__
#define __NOUVEAU_CONTEXT_H__
unsigned int
nouveau_is_texture_referenced(struct pipe_context *, struct pipe_texture *,
unsigned face, unsigned level);
unsigned int
nouveau_is_buffer_referenced(struct pipe_context *, struct pipe_buffer *);
#endif
......@@ -32,28 +32,9 @@ nouveau_screen_get_vendor(struct pipe_screen *pscreen)
return "nouveau";
}
static struct pipe_buffer *
nouveau_screen_bo_skel(struct pipe_screen *pscreen, struct nouveau_bo *bo,
unsigned alignment, unsigned usage, unsigned size)
{
struct pipe_buffer *pb;
pb = CALLOC(1, sizeof(struct pipe_buffer)+sizeof(struct nouveau_bo *));
if (!pb) {
nouveau_bo_ref(NULL, &bo);
return NULL;
}
pipe_reference_init(&pb->reference, 1);
pb->screen = pscreen;
pb->alignment = alignment;
pb->usage = usage;
pb->size = size;
*(struct nouveau_bo **)(pb + 1) = bo;
return pb;
}
static struct pipe_buffer *
struct nouveau_bo *
nouveau_screen_bo_new(struct pipe_screen *pscreen, unsigned alignment,
unsigned usage, unsigned size)
{
......@@ -93,10 +74,10 @@ nouveau_screen_bo_new(struct pipe_screen *pscreen, unsigned alignment,
if (ret)
return NULL;
return nouveau_screen_bo_skel(pscreen, bo, alignment, usage, size);
return bo;
}
static struct pipe_buffer *
struct nouveau_bo *
nouveau_screen_bo_user(struct pipe_screen *pscreen, void *ptr, unsigned bytes)
{
struct nouveau_device *dev = nouveau_screen(pscreen)->device;
......@@ -107,7 +88,7 @@ nouveau_screen_bo_user(struct pipe_screen *pscreen, void *ptr, unsigned bytes)
if (ret)
return NULL;
return nouveau_screen_bo_skel(pscreen, bo, 0, 0, bytes);
return bo;
}
static inline uint32_t
......@@ -130,23 +111,14 @@ nouveau_screen_map_flags(unsigned pipe)
return flags;
}
static void *
nouveau_screen_bo_map(struct pipe_screen *pscreen, struct pipe_buffer *pb,
void *
nouveau_screen_bo_map(struct pipe_screen *pscreen,
struct nouveau_bo *pb,
unsigned usage)
{
struct nouveau_bo *bo = nouveau_bo(pb);
struct nouveau_screen *nscreen = nouveau_screen(pscreen);
int ret;
if (nscreen->pre_pipebuffer_map_callback) {
ret = nscreen->pre_pipebuffer_map_callback(pscreen, pb, usage);
if (ret) {
debug_printf("pre_pipebuffer_map_callback failed %d\n",
ret);
return NULL;
}
}
ret = nouveau_bo_map(bo, nouveau_screen_map_flags(usage));
if (ret) {
debug_printf("map failed: %d\n", ret);
......@@ -156,24 +128,14 @@ nouveau_screen_bo_map(struct pipe_screen *pscreen, struct pipe_buffer *pb,
return bo->map;
}
static void *
nouveau_screen_bo_map_range(struct pipe_screen *pscreen, struct pipe_buffer *pb,
void *
nouveau_screen_bo_map_range(struct pipe_screen *pscreen, struct nouveau_bo *bo,
unsigned offset, unsigned length, unsigned usage)
{
struct nouveau_bo *bo = nouveau_bo(pb);
struct nouveau_screen *nscreen = nouveau_screen(pscreen);
uint32_t flags = nouveau_screen_map_flags(usage);
int ret;
if (nscreen->pre_pipebuffer_map_callback) {
ret = nscreen->pre_pipebuffer_map_callback(pscreen, pb, usage);
if (ret) {
debug_printf("pre_pipebuffer_map_callback failed %d\n",
ret);
return NULL;
}
}
ret = nouveau_bo_map_range(bo, offset, length, flags);
if (ret) {
nouveau_bo_unmap(bo);
......@@ -185,30 +147,23 @@ nouveau_screen_bo_map_range(struct pipe_screen *pscreen, struct pipe_buffer *pb,
return (char *)bo->map - offset; /* why gallium? why? */
}
static void
nouveau_screen_bo_map_flush(struct pipe_screen *pscreen, struct pipe_buffer *pb,
unsigned offset, unsigned length)
void
nouveau_screen_bo_map_flush_range(struct pipe_screen *pscreen, struct nouveau_bo *bo,
unsigned offset, unsigned length)
{
struct nouveau_bo *bo = nouveau_bo(pb);
nouveau_bo_map_flush(bo, offset, length);
}
static void
nouveau_screen_bo_unmap(struct pipe_screen *pscreen, struct pipe_buffer *pb)
void
nouveau_screen_bo_unmap(struct pipe_screen *pscreen, struct nouveau_bo *bo)
{
struct nouveau_bo *bo = nouveau_bo(pb);
nouveau_bo_unmap(bo);
}
static void
nouveau_screen_bo_del(struct pipe_buffer *pb)
void
nouveau_screen_bo_release(struct pipe_screen *pscreen, struct nouveau_bo *bo)
{
struct nouveau_bo *bo = nouveau_bo(pb);
nouveau_bo_ref(NULL, &bo);
FREE(pb);
}
static void
......@@ -236,59 +191,32 @@ nouveau_screen_fence_finish(struct pipe_screen *screen,
}
/*
* Both texture_{from|get}_handle use drm api defines directly which they
* shouldn't do. The problem is that from|get are pipe functions and as
* such they should be defined in the pipe level. If nouveau had a propper
* winsys interface we would have added from|get to that interface using
* the winsys_handle struct as done with other drivers. However this code
* calls directly into the libdrm_nouveau.so functions (nouveau_bo_*). So
* we need to translate the handle into something they understand.
*/
static struct pipe_texture *
nouveau_screen_texture_from_handle(struct pipe_screen *pscreen,
const struct pipe_texture *templ,
struct winsys_handle *whandle)
struct nouveau_bo *
nouveau_screen_bo_from_handle(struct pipe_screen *pscreen,
struct winsys_handle *whandle,
unsigned *out_stride)
{
struct nouveau_device *dev = nouveau_screen(pscreen)->device;
struct pipe_texture *pt;
struct pipe_buffer *pb;
int ret;
pb = CALLOC(1, sizeof(struct pipe_buffer) + sizeof(struct nouveau_bo*));
if (!pb)
return NULL;
ret = nouveau_bo_handle_ref(dev, whandle->handle, (struct nouveau_bo**)(pb+1));
struct nouveau_bo *bo;
ret = nouveau_bo_handle_ref(dev, whandle->handle, &bo);
if (ret) {
debug_printf("%s: ref name 0x%08x failed with %d\n",
__func__, whandle->handle, ret);
FREE(pb);
return NULL;
}
pipe_reference_init(&pb->reference, 1);
pb->screen = pscreen;
pb->alignment = 0;
pb->usage = PIPE_BUFFER_USAGE_GPU_READ_WRITE |
PIPE_BUFFER_USAGE_CPU_READ_WRITE;
pb->size = nouveau_bo(pb)->size;
pt = nouveau_screen(pscreen)->texture_blanket(pscreen, templ,
&whandle->stride, pb);
pipe_buffer_reference(&pb, NULL);
return pt;
*out_stride = whandle->stride;
return bo;
}
static boolean
nouveau_screen_texture_get_handle(struct pipe_screen *pscreen,
struct pipe_texture *pt,
struct winsys_handle *whandle)
{
struct nouveau_miptree *mt = nouveau_miptree(pt);
if (!mt || !mt->bo)
return false;
boolean
nouveau_screen_bo_get_handle(struct pipe_screen *pscreen,
struct nouveau_bo *bo,
unsigned stride,
struct winsys_handle *whandle)
{
whandle->stride = util_format_get_stride(mt->base.format, mt->base.width0);
if (whandle->type == DRM_API_HANDLE_TYPE_SHARED) {
......@@ -301,6 +229,26 @@ nouveau_screen_texture_get_handle(struct pipe_screen *pscreen,
}
}
unsigned int
nouveau_reference_flags(struct nouveau_bo *bo)
{
uint32_t bo_flags;
int flags = 0;
bo_flags = nouveau_bo_pending(bo);
if (bo_flags & NOUVEAU_BO_RD)
flags |= PIPE_REFERENCED_FOR_READ;
if (bo_flags & NOUVEAU_BO_WR)
flags |= PIPE_REFERENCED_FOR_WRITE;
return flags;
}
int
nouveau_screen_init(struct nouveau_screen *screen, struct nouveau_device *dev)
{
......@@ -316,21 +264,10 @@ nouveau_screen_init(struct nouveau_screen *screen, struct nouveau_device *dev)
pscreen->get_name = nouveau_screen_get_name;
pscreen->get_vendor = nouveau_screen_get_vendor;
pscreen->buffer_create = nouveau_screen_bo_new;
pscreen->user_buffer_create = nouveau_screen_bo_user;
pscreen->buffer_map = nouveau_screen_bo_map;
pscreen->buffer_map_range = nouveau_screen_bo_map_range;
pscreen->buffer_flush_mapped_range = nouveau_screen_bo_map_flush;
pscreen->buffer_unmap = nouveau_screen_bo_unmap;
pscreen->buffer_destroy = nouveau_screen_bo_del;
pscreen->fence_reference = nouveau_screen_fence_ref;
pscreen->fence_signalled = nouveau_screen_fence_signalled;
pscreen->fence_finish = nouveau_screen_fence_finish;
pscreen->texture_from_handle = nouveau_screen_texture_from_handle;
pscreen->texture_get_handle = nouveau_screen_texture_get_handle;
return 0;
}
......
......@@ -5,21 +5,6 @@ struct nouveau_screen {
struct pipe_screen base;
struct nouveau_device *device;
struct nouveau_channel *channel;
/**
* Create a new texture object, using the given template info, but on top of
* existing memory.
*
* It is assumed that the buffer data is layed out according to the expected
* by the hardware. NULL will be returned if any inconsistency is found.
*/
struct pipe_texture * (*texture_blanket)(struct pipe_screen *,
const struct pipe_texture *templat,
const unsigned *stride,
struct pipe_buffer *buffer);
int (*pre_pipebuffer_map_callback) (struct pipe_screen *pscreen,
struct pipe_buffer *pb, unsigned usage);
};
static inline struct nouveau_screen *
......@@ -28,24 +13,51 @@ nouveau_screen(struct pipe_screen *pscreen)
return (struct nouveau_screen *)pscreen;
}
static inline struct nouveau_bo *
nouveau_bo(struct pipe_buffer *pb)
{
return pb ? *(struct nouveau_bo **)(pb + 1) : NULL;
}
/* Not really sure if this is needed, or whether the individual
* drivers are happy to talk to the bo functions themselves. In a way
* this is what we'd expect from a regular winsys interface.
*/
struct nouveau_bo *
nouveau_screen_bo_new(struct pipe_screen *pscreen, unsigned alignment,
unsigned usage, unsigned size);
struct nouveau_bo *
nouveau_screen_bo_user(struct pipe_screen *pscreen, void *ptr, unsigned bytes);
void *
nouveau_screen_bo_map(struct pipe_screen *pscreen,
struct nouveau_bo *pb,
unsigned usage);
void *
nouveau_screen_bo_map_range(struct pipe_screen *pscreen, struct nouveau_bo *bo,
unsigned offset, unsigned length, unsigned usage);
void
nouveau_screen_bo_map_flush_range(struct pipe_screen *pscreen, struct nouveau_bo *bo,
unsigned offset, unsigned length);
void
nouveau_screen_bo_unmap(struct pipe_screen *pscreen, struct nouveau_bo *bo);
void
nouveau_screen_bo_release(struct pipe_screen *pscreen, struct nouveau_bo *bo);
boolean
nouveau_screen_bo_get_handle(struct pipe_screen *pscreen,
struct nouveau_bo *bo,
unsigned stride,
struct winsys_handle *whandle);
struct nouveau_bo *
nouveau_screen_bo_from_handle(struct pipe_screen *pscreen,
struct winsys_handle *whandle,
unsigned *out_stride);
unsigned int
nouveau_reference_flags(struct nouveau_bo *bo);
int nouveau_screen_init(struct nouveau_screen *, struct nouveau_device *);
void nouveau_screen_fini(struct nouveau_screen *);
struct nouveau_miptree {
struct pipe_texture base;
struct nouveau_bo *bo;
};
static inline struct nouveau_miptree *
nouveau_miptree(struct pipe_texture *pt)
{
return (struct nouveau_miptree *)pt;
}
#endif
......@@ -98,9 +98,9 @@ struct u_split_prim {
unsigned p_start;
unsigned p_end;
int repeat_first:1;
int close_first:1;
int edgeflag_off:1;
uint repeat_first:1;
uint close_first:1;
uint edgeflag_off:1;
};
static inline void
......
......@@ -2,7 +2,6 @@
#define NOUVEAU_WINSYS_H
#include <stdint.h>
#include "util/u_simple_screen.h"
#include "pipe/p_defines.h"
#include "nouveau/nouveau_bo.h"
......
......@@ -4,12 +4,14 @@ include $(TOP)/configs/current
LIBNAME = nv50
C_SOURCES = \
nv50_buffer.c \
nv50_clear.c \
nv50_context.c \
nv50_draw.c \
nv50_miptree.c \
nv50_query.c \
nv50_program.c \
nv50_resource.c \
nv50_screen.c \
nv50_state.c \
nv50_state_validate.c \
......
#include "util/u_inlines.h"
#include "util/u_memory.h"
#include "util/u_math.h"
#include "nouveau/nouveau_screen.h"
#include "nv50_resource.h"
static void nv50_buffer_destroy(struct pipe_screen *pscreen,
struct pipe_resource *presource)
{
struct nv50_resource *buffer = nv50_resource(presource);
nouveau_screen_bo_release(pscreen, buffer->bo);
FREE(buffer);
}
/* Utility functions for transfer create/destroy are hooked in and
* just record the arguments to those functions.
*/
static void *
nv50_buffer_transfer_map( struct pipe_context *pipe,
struct pipe_transfer *transfer )
{
struct nv50_resource *buffer = nv50_resource(transfer->resource);
uint8_t *map;
map = nouveau_screen_bo_map_range( pipe->screen,
buffer->bo,
transfer->box.x,
transfer->box.width,
transfer->usage );
if (map == NULL)
return NULL;
return map + transfer->box.x;
}
static void nv50_buffer_transfer_flush_region( struct pipe_context *pipe,
struct pipe_transfer *transfer,
const struct pipe_box *box)
{
struct nv50_resource *buffer = nv50_resource(transfer->resource);
nouveau_screen_bo_map_flush_range(pipe->screen,
buffer->bo,
transfer->box.x + box->x,
box->width);
}
static void nv50_buffer_transfer_unmap( struct pipe_context *pipe,
struct pipe_transfer *transfer )
{
struct nv50_resource *buffer = nv50_resource(transfer->resource);
nouveau_screen_bo_unmap(pipe->screen, buffer->bo);
}
struct u_resource_vtbl nv50_buffer_vtbl =
{
u_default_resource_get_handle, /* get_handle */
nv50_buffer_destroy, /* resource_destroy */
NULL, /* is_resource_referenced */
u_default_get_transfer, /* get_transfer */
u_default_transfer_destroy, /* transfer_destroy */
nv50_buffer_transfer_map, /* transfer_map */
nv50_buffer_transfer_flush_region, /* transfer_flush_region */
nv50_buffer_transfer_unmap, /* transfer_unmap */
u_default_transfer_inline_write /* transfer_inline_write */
};
struct pipe_resource *
nv50_buffer_create(struct pipe_screen *pscreen,
const struct pipe_resource *template)
{
struct nv50_resource *buffer;
buffer = CALLOC_STRUCT(nv50_resource);
if (!buffer)
return NULL;
buffer->base = *template;
buffer->vtbl = &nv50_buffer_vtbl;
pipe_reference_init(&buffer->base.reference, 1);
buffer->base.screen = pscreen;
buffer->bo = nouveau_screen_bo_new(pscreen,
16,
buffer->base.usage,
buffer->base.width0);
if (buffer->bo == NULL)
goto fail;
return &buffer->base;
fail:
FREE(buffer);
return NULL;
}
struct pipe_resource *
nv50_user_buffer_create(struct pipe_screen *pscreen,
void *ptr,
unsigned bytes,
unsigned usage)
{
struct nv50_resource *buffer;
buffer = CALLOC_STRUCT(nv50_resource);
if (!buffer)
return NULL;
pipe_reference_init(&buffer->base.reference, 1);
buffer->vtbl = &nv50_buffer_vtbl;
buffer->base.screen = pscreen;
buffer->base.format = PIPE_FORMAT_R8_UNORM;
buffer->base.usage = usage;
buffer->base.width0 = bytes;
buffer->base.height0 = 1;
buffer->base.depth0 = 1;
buffer->bo = nouveau_screen_bo_user(pscreen, ptr, bytes);
if (!buffer->bo)
goto fail;
return &buffer->base;
fail:
FREE(buffer);
return NULL;
}
......@@ -89,9 +89,6 @@ nv50_create(struct pipe_screen *pscreen, void *priv)
nv50->pipe.flush = nv50_flush;
nv50->pipe.is_texture_referenced = nouveau_is_texture_referenced;
nv50->pipe.is_buffer_referenced = nouveau_is_buffer_referenced;
screen->base.channel->user_private = nv50;
nv50_init_surface_functions(nv50);
......
......@@ -16,7 +16,6 @@
#include "nouveau/nouveau_winsys.h"
#include "nouveau/nouveau_gldefs.h"
#include "nouveau/nouveau_stateobj.h"
#include "nouveau/nouveau_context.h"
#include "nv50_screen.h"
#include "nv50_program.h"
......@@ -101,27 +100,6 @@ get_tile_depth(uint32_t tile_mode)
return 1 << (tile_mode >> 4);
}
struct nv50_miptree_level {
int *image_offset;
unsigned pitch;
unsigned tile_mode;
};
#define NV50_MAX_TEXTURE_LEVELS 16
struct nv50_miptree {
struct nouveau_miptree base;
struct nv50_miptree_level level[NV50_MAX_TEXTURE_LEVELS];
int image_nr;
int total_size;
};
static INLINE struct nv50_miptree *
nv50_miptree(struct pipe_texture *pt)
{
return (struct nv50_miptree *)pt;
}
struct nv50_surface {
struct pipe_surface base;
......@@ -165,7 +143,7 @@ struct nv50_context {
struct nv50_program *vertprog;
struct nv50_program *fragprog;
struct nv50_program *geomprog;
struct pipe_buffer *constbuf[PIPE_SHADER_TYPES];
struct pipe_resource *constbuf[PIPE_SHADER_TYPES];
struct pipe_vertex_buffer vtxbuf[PIPE_MAX_ATTRIBS];
unsigned vtxbuf_nr;
struct nv50_vtxelt_stateobj *vtxelt;
......@@ -206,12 +184,12 @@ extern void nv50_draw_arrays_instanced(struct pipe_context *, unsigned mode,
unsigned startInstance,
unsigned instanceCount);
extern void nv50_draw_elements(struct pipe_context *pipe,
struct pipe_buffer *indexBuffer,
struct pipe_resource *indexBuffer,
unsigned indexSize,
unsigned mode, unsigned start,
unsigned count);
extern void nv50_draw_elements_instanced(struct pipe_context *pipe,
struct pipe_buffer *indexBuffer,
struct pipe_resource *indexBuffer,
unsigned indexSize,
unsigned mode, unsigned start,
unsigned count,
......@@ -222,7 +200,7 @@ extern struct nouveau_stateobj *nv50_vbo_validate(struct nv50_context *nv50);
/* nv50_push.c */
extern void
nv50_push_elements_instanced(struct pipe_context *, struct pipe_buffer *,
nv50_push_elements_instanced(struct pipe_context *, struct pipe_resource *,
unsigned idxsize, unsigned mode, unsigned start,
unsigned count, unsigned i_start,
unsigned i_count);
......@@ -258,13 +236,6 @@ extern boolean nv50_tex_construct(struct nv50_sampler_view *view);
extern void nv50_tex_relocs(struct nv50_context *);
extern struct nouveau_stateobj *nv50_tex_validate(struct nv50_context *);
/* nv50_transfer.c */
extern void
nv50_upload_sifc(struct nv50_context *nv50,
struct nouveau_bo *bo, unsigned dst_offset, unsigned reloc,
unsigned dst_format, int dst_w, int dst_h, int dst_pitch,