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) 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); 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, GLbitfield storageFlags, 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 obj->StorageFlags = storageFlags; 85 86 /* Free previous storage */ 87 nouveau_bo_ref(NULL, &nbo->bo); 88 free(nbo->sys); 89 nbo->sys = NULL; 90 91 if (target == GL_ELEMENT_ARRAY_BUFFER_ARB || 92 (size < 512 && usage == GL_DYNAMIC_DRAW_ARB) || 93 context_chipset(ctx) < 0x10) { 94 /* Heuristic: keep it in system ram */ 95 nbo->sys = malloc(size); 96 97 } else { 98 /* Get a hardware BO */ 99 ret = nouveau_bo_new(context_dev(ctx), 100 NOUVEAU_BO_GART | NOUVEAU_BO_MAP, 101 ctx->Const.MinMapBufferAlignment, 102 size, NULL, &nbo->bo); 103 assert(!ret); 104 } 105 106 if (data) 107 memcpy(get_bufferobj_map(ctx, obj, NOUVEAU_BO_WR), data, size); 108 109 return GL_TRUE; 110 } 111 112 static void 113 nouveau_bufferobj_subdata(struct gl_context *ctx, GLintptrARB offset, 114 GLsizeiptrARB size, const GLvoid *data, 115 struct gl_buffer_object *obj) 116 { 117 memcpy(get_bufferobj_map(ctx, obj, NOUVEAU_BO_WR) + offset, data, size); 118 } 119 120 static void 121 nouveau_bufferobj_get_subdata(struct gl_context *ctx, GLintptrARB offset, 122 GLsizeiptrARB size, GLvoid *data, 123 struct gl_buffer_object *obj) 124 { 125 memcpy(data, get_bufferobj_map(ctx, obj, NOUVEAU_BO_RD) + offset, size); 126 } 127 128 static void * 129 nouveau_bufferobj_map_range(struct gl_context *ctx, GLintptr offset, 130 GLsizeiptr length, GLbitfield access, 131 struct gl_buffer_object *obj, 132 gl_map_buffer_index index) 133 { 134 unsigned flags = 0; 135 char *map; 136 137 assert(!obj->Mappings[index].Pointer); 138 139 if (!(access & GL_MAP_UNSYNCHRONIZED_BIT)) { 140 if (access & GL_MAP_READ_BIT) 141 flags |= NOUVEAU_BO_RD; 142 if (access & GL_MAP_WRITE_BIT) 143 flags |= NOUVEAU_BO_WR; 144 } 145 146 map = get_bufferobj_map(ctx, obj, flags); 147 if (!map) 148 return NULL; 149 150 obj->Mappings[index].Pointer = map + offset; 151 obj->Mappings[index].Offset = offset; 152 obj->Mappings[index].Length = length; 153 obj->Mappings[index].AccessFlags = access; 154 155 return obj->Mappings[index].Pointer; 156 } 157 158 static GLboolean 159 nouveau_bufferobj_unmap(struct gl_context *ctx, struct gl_buffer_object *obj, 160 gl_map_buffer_index index) 161 { 162 assert(obj->Mappings[index].Pointer); 163 164 obj->Mappings[index].Pointer = NULL; 165 obj->Mappings[index].Offset = 0; 166 obj->Mappings[index].Length = 0; 167 obj->Mappings[index].AccessFlags = 0; 168 169 return GL_TRUE; 170 } 171 172 void 173 nouveau_bufferobj_functions_init(struct dd_function_table *functions) 174 { 175 functions->NewBufferObject = nouveau_bufferobj_new; 176 functions->DeleteBuffer = nouveau_bufferobj_del; 177 functions->BufferData = nouveau_bufferobj_data; 178 functions->BufferSubData = nouveau_bufferobj_subdata; 179 functions->GetBufferSubData = nouveau_bufferobj_get_subdata; 180 functions->MapBufferRange = nouveau_bufferobj_map_range; 181 functions->UnmapBuffer = nouveau_bufferobj_unmap; 182 } 183