static void wined3d_volume_evict_sysmem(struct wined3d_volume *volume) { wined3d_resource_free_sysmem(volume->resource.heap_memory); volume->resource.heap_memory = NULL; volume->resource.allocatedMemory = NULL; wined3d_volume_invalidate_location(volume, WINED3D_LOCATION_SYSMEM); }
static void volume_unload(struct wined3d_resource *resource) { struct wined3d_volume *volume = volume_from_resource(resource); struct wined3d_device *device = volume->resource.device; struct wined3d_context *context; if (volume->resource.pool == WINED3D_POOL_DEFAULT) ERR("Unloading DEFAULT pool volume.\n"); TRACE("texture %p.\n", resource); if (volume_prepare_system_memory(volume)) { context = context_acquire(device, NULL); wined3d_volume_load_location(volume, context, WINED3D_LOCATION_SYSMEM); context_release(context); wined3d_volume_invalidate_location(volume, ~WINED3D_LOCATION_SYSMEM); } else { ERR("Out of memory when unloading volume %p.\n", volume); wined3d_volume_validate_location(volume, WINED3D_LOCATION_DISCARDED); wined3d_volume_invalidate_location(volume, ~WINED3D_LOCATION_DISCARDED); } if (volume->pbo) { /* Should not happen because only dynamic default pool volumes * have a buffer, and those are not evicted by device_evit_managed_resources * and must be freed before a non-ex device reset. */ ERR("Unloading a volume with a buffer\n"); wined3d_volume_free_pbo(volume); } /* The texture name is managed by the container. */ volume->flags &= ~(WINED3D_VFLAG_ALLOCATED | WINED3D_VFLAG_SRGB_ALLOCATED | WINED3D_VFLAG_CLIENT_STORAGE); resource_unload(resource); }
HRESULT CDECL wined3d_volume_map(struct wined3d_volume *volume, struct wined3d_map_desc *map_desc, const struct wined3d_box *box, DWORD flags) { struct wined3d_device *device = volume->resource.device; struct wined3d_context *context; const struct wined3d_gl_info *gl_info; BYTE *base_memory; TRACE("volume %p, map_desc %p, box %p, flags %#x.\n", volume, map_desc, box, flags); if (!(volume->resource.access_flags & WINED3D_RESOURCE_ACCESS_CPU)) { WARN("Volume %p is not CPU accessible.\n", volume); map_desc->data = NULL; return WINED3DERR_INVALIDCALL; } flags = wined3d_resource_sanitize_map_flags(&volume->resource, flags); if (volume->flags & WINED3D_VFLAG_PBO) { context = context_acquire(device, NULL); gl_info = context->gl_info; wined3d_volume_prepare_pbo(volume, context); if (flags & WINED3D_MAP_DISCARD) wined3d_volume_validate_location(volume, WINED3D_LOCATION_BUFFER); else wined3d_volume_load_location(volume, context, WINED3D_LOCATION_BUFFER); GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, volume->pbo)); if (gl_info->supported[ARB_MAP_BUFFER_RANGE]) { GLbitfield mapflags = wined3d_resource_gl_map_flags(flags); mapflags &= ~GL_MAP_FLUSH_EXPLICIT_BIT; base_memory = GL_EXTCALL(glMapBufferRange(GL_PIXEL_UNPACK_BUFFER_ARB, 0, volume->resource.size, mapflags)); } else { base_memory = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0)); } GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0)); checkGLcall("Map PBO"); context_release(context); } else { if (!volume_prepare_system_memory(volume)) { WARN("Out of memory.\n"); map_desc->data = NULL; return E_OUTOFMEMORY; } if (flags & WINED3D_MAP_DISCARD) { wined3d_volume_validate_location(volume, WINED3D_LOCATION_SYSMEM); } else if (!(volume->locations & WINED3D_LOCATION_SYSMEM)) { context = context_acquire(device, NULL); wined3d_volume_load_location(volume, context, WINED3D_LOCATION_SYSMEM); context_release(context); } base_memory = volume->resource.allocatedMemory; } TRACE("Base memory pointer %p.\n", base_memory); map_desc->row_pitch = volume->resource.format->byte_count * volume->resource.width; /* Bytes / row */ map_desc->slice_pitch = volume->resource.format->byte_count * volume->resource.width * volume->resource.height; /* Bytes / slice */ if (!box) { TRACE("No box supplied - all is ok\n"); map_desc->data = base_memory; } else { TRACE("Lock Box (%p) = l %u, t %u, r %u, b %u, fr %u, ba %u\n", box, box->left, box->top, box->right, box->bottom, box->front, box->back); map_desc->data = base_memory + (map_desc->slice_pitch * box->front) /* FIXME: is front < back or vica versa? */ + (map_desc->row_pitch * box->top) + (box->left * volume->resource.format->byte_count); } if (!(flags & (WINED3D_MAP_NO_DIRTY_UPDATE | WINED3D_MAP_READONLY))) { wined3d_texture_set_dirty(volume->container, TRUE); if (volume->flags & WINED3D_VFLAG_PBO) wined3d_volume_invalidate_location(volume, ~WINED3D_LOCATION_BUFFER); else wined3d_volume_invalidate_location(volume, ~WINED3D_LOCATION_SYSMEM); } volume->flags |= WINED3D_VFLAG_LOCKED; TRACE("Returning memory %p, row pitch %d, slice pitch %d.\n", map_desc->data, map_desc->row_pitch, map_desc->slice_pitch); return WINED3D_OK; }
/* Context activation is done by the caller. */ static void wined3d_volume_load_location(struct wined3d_volume *volume, struct wined3d_context *context, DWORD location) { DWORD required_access = volume_access_from_location(location); TRACE("Volume %p, loading %s, have %s.\n", volume, wined3d_debug_location(location), wined3d_debug_location(volume->locations)); if ((volume->locations & location) == location) { TRACE("Location(s) already up to date.\n"); return; } if ((volume->resource.access_flags & required_access) != required_access) { ERR("Operation requires %#x access, but volume only has %#x.\n", required_access, volume->resource.access_flags); return; } switch (location) { case WINED3D_LOCATION_TEXTURE_RGB: case WINED3D_LOCATION_TEXTURE_SRGB: if ((location == WINED3D_LOCATION_TEXTURE_RGB && !(volume->flags & WINED3D_VFLAG_ALLOCATED)) || (location == WINED3D_LOCATION_TEXTURE_SRGB && !(volume->flags & WINED3D_VFLAG_SRGB_ALLOCATED))) ERR("Trying to load (s)RGB texture without prior allocation.\n"); if (volume->locations & WINED3D_LOCATION_DISCARDED) { TRACE("Volume previously discarded, nothing to do.\n"); wined3d_volume_invalidate_location(volume, WINED3D_LOCATION_DISCARDED); } else if (volume->locations & WINED3D_LOCATION_SYSMEM) { struct wined3d_bo_address data = {0, volume->resource.allocatedMemory}; wined3d_volume_upload_data(volume, context, &data); } else if (volume->locations & WINED3D_LOCATION_BUFFER) { struct wined3d_bo_address data = {volume->pbo, NULL}; wined3d_volume_upload_data(volume, context, &data); } else if (volume->locations & WINED3D_LOCATION_TEXTURE_RGB) { wined3d_volume_srgb_transfer(volume, context, TRUE); } else if (volume->locations & WINED3D_LOCATION_TEXTURE_SRGB) { wined3d_volume_srgb_transfer(volume, context, FALSE); } else { FIXME("Implement texture loading from %s.\n", wined3d_debug_location(volume->locations)); return; } wined3d_volume_validate_location(volume, location); if (volume->resource.pool == WINED3D_POOL_MANAGED && volume->download_count < 10) wined3d_volume_evict_sysmem(volume); break; case WINED3D_LOCATION_SYSMEM: if (!volume->resource.allocatedMemory || !volume->resource.heap_memory) { ERR("Trying to load WINED3D_LOCATION_SYSMEM without setting it up first.\n"); return; } if (volume->locations & WINED3D_LOCATION_DISCARDED) { TRACE("Volume previously discarded, nothing to do.\n"); wined3d_volume_invalidate_location(volume, WINED3D_LOCATION_DISCARDED); } else if (volume->locations & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB)) { struct wined3d_bo_address data = {0, volume->resource.allocatedMemory}; if (volume->locations & WINED3D_LOCATION_TEXTURE_RGB) volume_bind_and_dirtify(volume, context, FALSE); else volume_bind_and_dirtify(volume, context, TRUE); volume->download_count++; wined3d_volume_download_data(volume, context, &data); } else { FIXME("Implement WINED3D_LOCATION_SYSMEM loading from %s.\n", wined3d_debug_location(volume->locations)); return; } wined3d_volume_validate_location(volume, WINED3D_LOCATION_SYSMEM); break; case WINED3D_LOCATION_BUFFER: if (!volume->pbo || !(volume->flags & WINED3D_VFLAG_PBO)) ERR("Trying to load WINED3D_LOCATION_BUFFER without setting it up first.\n"); if (volume->locations & WINED3D_LOCATION_DISCARDED) { TRACE("Volume previously discarded, nothing to do.\n"); wined3d_volume_invalidate_location(volume, WINED3D_LOCATION_DISCARDED); } else if (volume->locations & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB)) { struct wined3d_bo_address data = {volume->pbo, NULL}; if (volume->locations & WINED3D_LOCATION_TEXTURE_RGB) volume_bind_and_dirtify(volume, context, FALSE); else volume_bind_and_dirtify(volume, context, TRUE); wined3d_volume_download_data(volume, context, &data); } else { FIXME("Implement WINED3D_LOCATION_BUFFER loading from %s.\n", wined3d_debug_location(volume->locations)); return; } wined3d_volume_validate_location(volume, WINED3D_LOCATION_BUFFER); break; default: FIXME("Implement %s loading from %s.\n", wined3d_debug_location(location), wined3d_debug_location(volume->locations)); } }
HRESULT CDECL wined3d_volume_map(struct wined3d_volume *volume, struct wined3d_map_desc *map_desc, const struct wined3d_box *box, DWORD flags) { struct wined3d_device *device = volume->resource.device; struct wined3d_context *context; const struct wined3d_gl_info *gl_info; BYTE *base_memory; const struct wined3d_format *format = volume->resource.format; TRACE("volume %p, map_desc %p, box %p, flags %#x.\n", volume, map_desc, box, flags); map_desc->data = NULL; if (!(volume->resource.access_flags & WINED3D_RESOURCE_ACCESS_CPU)) { WARN("Volume %p is not CPU accessible.\n", volume); return WINED3DERR_INVALIDCALL; } if (volume->resource.map_count) { WARN("Volume is already mapped.\n"); return WINED3DERR_INVALIDCALL; } if (!wined3d_volume_check_box_dimensions(volume, box)) { WARN("Map box is invalid.\n"); return WINED3DERR_INVALIDCALL; } if ((format->flags & WINED3DFMT_FLAG_BLOCKS) && !volume_check_block_align(volume, box)) { WARN("Map box is misaligned for %ux%u blocks.\n", format->block_width, format->block_height); return WINED3DERR_INVALIDCALL; } flags = wined3d_resource_sanitize_map_flags(&volume->resource, flags); if (volume->flags & WINED3D_VFLAG_PBO) { context = context_acquire(device, NULL); gl_info = context->gl_info; wined3d_volume_prepare_pbo(volume, context); if (flags & WINED3D_MAP_DISCARD) wined3d_volume_validate_location(volume, WINED3D_LOCATION_BUFFER); else wined3d_volume_load_location(volume, context, WINED3D_LOCATION_BUFFER); GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, volume->pbo)); if (gl_info->supported[ARB_MAP_BUFFER_RANGE]) { GLbitfield mapflags = wined3d_resource_gl_map_flags(flags); mapflags &= ~GL_MAP_FLUSH_EXPLICIT_BIT; base_memory = GL_EXTCALL(glMapBufferRange(GL_PIXEL_UNPACK_BUFFER_ARB, 0, volume->resource.size, mapflags)); } else { GLenum access = wined3d_resource_gl_legacy_map_flags(flags); base_memory = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, access)); } GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0)); checkGLcall("Map PBO"); context_release(context); } else { if (!volume_prepare_system_memory(volume)) { WARN("Out of memory.\n"); map_desc->data = NULL; return E_OUTOFMEMORY; } if (flags & WINED3D_MAP_DISCARD) { wined3d_volume_validate_location(volume, WINED3D_LOCATION_SYSMEM); } else if (!(volume->locations & WINED3D_LOCATION_SYSMEM)) { context = context_acquire(device, NULL); wined3d_volume_load_location(volume, context, WINED3D_LOCATION_SYSMEM); context_release(context); } base_memory = volume->resource.heap_memory; } TRACE("Base memory pointer %p.\n", base_memory); if (format->flags & WINED3DFMT_FLAG_BROKEN_PITCH) { map_desc->row_pitch = volume->resource.width * format->byte_count; map_desc->slice_pitch = map_desc->row_pitch * volume->resource.height; } else { wined3d_volume_get_pitch(volume, &map_desc->row_pitch, &map_desc->slice_pitch); } if (!box) { TRACE("No box supplied - all is ok\n"); map_desc->data = base_memory; } else { TRACE("Lock Box (%p) = l %u, t %u, r %u, b %u, fr %u, ba %u\n", box, box->left, box->top, box->right, box->bottom, box->front, box->back); if ((format->flags & (WINED3DFMT_FLAG_BLOCKS | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_BLOCKS) { /* Compressed textures are block based, so calculate the offset of * the block that contains the top-left pixel of the locked rectangle. */ map_desc->data = base_memory + (box->front * map_desc->slice_pitch) + ((box->top / format->block_height) * map_desc->row_pitch) + ((box->left / format->block_width) * format->block_byte_count); } else { map_desc->data = base_memory + (map_desc->slice_pitch * box->front) + (map_desc->row_pitch * box->top) + (box->left * volume->resource.format->byte_count); } } if (!(flags & (WINED3D_MAP_NO_DIRTY_UPDATE | WINED3D_MAP_READONLY))) { wined3d_texture_set_dirty(volume->container); if (volume->flags & WINED3D_VFLAG_PBO) wined3d_volume_invalidate_location(volume, ~WINED3D_LOCATION_BUFFER); else wined3d_volume_invalidate_location(volume, ~WINED3D_LOCATION_SYSMEM); } volume->resource.map_count++; TRACE("Returning memory %p, row pitch %d, slice pitch %d.\n", map_desc->data, map_desc->row_pitch, map_desc->slice_pitch); return WINED3D_OK; }
static void wined3d_volume_evict_sysmem(struct wined3d_volume *volume) { wined3d_resource_free_sysmem(&volume->resource); wined3d_volume_invalidate_location(volume, WINED3D_LOCATION_SYSMEM); }