1 /* 2 * Copyright (C) 2009 Francisco Jerez. 3 * All Rights Reserved. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining 6 * a copy of this software and associated documentation files (the 7 * "Software"), to deal in the Software without restriction, including 8 * without limitation the rights to use, copy, modify, merge, publish, 9 * distribute, sublicense, and/or sell copies of the Software, and to 10 * permit persons to whom the Software is furnished to do so, subject to 11 * the following conditions: 12 * 13 * The above copyright notice and this permission notice (including the 14 * next paragraph) shall be included in all copies or substantial 15 * portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE 21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 * 25 */ 26 27 #include "nouveau_driver.h" 28 #include "nouveau_bufferobj.h" 29 #include "nouveau_context.h" 30 31 #include "main/bufferobj.h" 32 33 static inline char * 34 get_bufferobj_map(struct gl_context *ctx, struct gl_buffer_object *obj, 35 unsigned flags) 36 { 37 struct nouveau_bufferobj *nbo = to_nouveau_bufferobj(obj); 38 void *map = NULL; 39 40 if (nbo->sys) { 41 map = nbo->sys; 42 } else if (nbo->bo) { 43 nouveau_bo_map(nbo->bo, flags, context_client(ctx)); 44 map = nbo->bo->map; 45 } 46 47 return map; 48 } 49 50 static struct gl_buffer_object * 51 nouveau_bufferobj_new(struct gl_context *ctx, GLuint buffer, GLenum target) 52 { 53 struct nouveau_bufferobj *nbo; 54 55 nbo = CALLOC_STRUCT(nouveau_bufferobj); 56 if (!nbo) 57 return NULL; 58 59 _mesa_initialize_buffer_object(ctx, &nbo->base, buffer, target); 60 61 return &nbo->base; 62 } 63 64 static void 65 nouveau_bufferobj_del(struct gl_context *ctx, struct gl_buffer_object *obj) 66 { 67 struct nouveau_bufferobj *nbo = to_nouveau_bufferobj(obj); 68 69 nouveau_bo_ref(NULL, &nbo->bo); 70 FREE(nbo->sys); 71 FREE(nbo); 72 } 73 74 static GLboolean 75 nouveau_bufferobj_data(struct gl_context *ctx, GLenum target, GLsizeiptrARB size, 76 const GLvoid *data, GLenum usage, 77 struct gl_buffer_object *obj) 78 { 79 struct nouveau_bufferobj *nbo = to_nouveau_bufferobj(obj); 80 int ret; 81 82 obj->Size = size; 83 obj->Usage = usage; 84 85 /* Free previous storage */ 86 nouveau_bo_ref(NULL, &nbo->bo); 87 FREE(nbo->sys); 88 89 if (target == GL_ELEMENT_ARRAY_BUFFER_ARB || 90 (size < 512 && usage == GL_DYNAMIC_DRAW_ARB) || 91 context_chipset(ctx) < 0x10) { 92 /* Heuristic: keep it in system ram */ 93 nbo->sys = MALLOC(size); 94 95 } else { 96 /* Get a hardware BO */ 97 ret = nouveau_bo_new(context_dev(ctx), 98 NOUVEAU_BO_GART | NOUVEAU_BO_MAP, 0, 99 size, NULL, &nbo->bo); 100 assert(!ret); 101 } 102 103 if (data) 104 memcpy(get_bufferobj_map(ctx, obj, NOUVEAU_BO_WR), data, size); 105 106 return GL_TRUE; 107 } 108 109 static void 110 nouveau_bufferobj_subdata(struct gl_context *ctx, GLintptrARB offset, 111 GLsizeiptrARB size, const GLvoid *data, 112 struct gl_buffer_object *obj) 113 { 114 memcpy(get_bufferobj_map(ctx, obj, NOUVEAU_BO_WR) + offset, data, size); 115 } 116 117 static void 118 nouveau_bufferobj_get_subdata(struct gl_context *ctx, GLintptrARB offset, 119 GLsizeiptrARB size, GLvoid *data, 120 struct gl_buffer_object *obj) 121 { 122 memcpy(data, get_bufferobj_map(ctx, obj, NOUVEAU_BO_RD) + offset, size); 123 } 124 125 static void * 126 nouveau_bufferobj_map_range(struct gl_context *ctx, GLintptr offset, 127 GLsizeiptr length, GLbitfield access, 128 struct gl_buffer_object *obj) 129 { 130 unsigned flags = 0; 131 char *map; 132 133 assert(!obj->Pointer); 134 135 if (!(access & GL_MAP_UNSYNCHRONIZED_BIT)) { 136 if (access & GL_MAP_READ_BIT) 137 flags |= NOUVEAU_BO_RD; 138 if (access & GL_MAP_WRITE_BIT) 139 flags |= NOUVEAU_BO_WR; 140 } 141 142 map = get_bufferobj_map(ctx, obj, flags); 143 if (!map) 144 return NULL; 145 146 obj->Pointer = map + offset; 147 obj->Offset = offset; 148 obj->Length = length; 149 obj->AccessFlags = access; 150 151 return obj->Pointer; 152 } 153 154 static GLboolean 155 nouveau_bufferobj_unmap(struct gl_context *ctx, struct gl_buffer_object *obj) 156 { 157 assert(obj->Pointer); 158 159 obj->Pointer = NULL; 160 obj->Offset = 0; 161 obj->Length = 0; 162 obj->AccessFlags = 0; 163 164 return GL_TRUE; 165 } 166 167 void 168 nouveau_bufferobj_functions_init(struct dd_function_table *functions) 169 { 170 functions->NewBufferObject = nouveau_bufferobj_new; 171 functions->DeleteBuffer = nouveau_bufferobj_del; 172 functions->BufferData = nouveau_bufferobj_data; 173 functions->BufferSubData = nouveau_bufferobj_subdata; 174 functions->GetBufferSubData = nouveau_bufferobj_get_subdata; 175 functions->MapBufferRange = nouveau_bufferobj_map_range; 176 functions->UnmapBuffer = nouveau_bufferobj_unmap; 177 } 178