wined3d: Implement Vulkan texture uploads.
[wine.git] / dlls / wined3d / texture.c
blob98bc8a510ce697bbca63acea682573e026bfce9c
1 /*
2 * Copyright 2002-2005 Jason Edmeades
3 * Copyright 2002-2005 Raphael Junqueira
4 * Copyright 2005 Oliver Stieber
5 * Copyright 2007-2009, 2013 Stefan Dösinger for CodeWeavers
6 * Copyright 2009-2011 Henri Verbeet for CodeWeavers
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "config.h"
24 #include "wine/port.h"
25 #include "wined3d_private.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
28 WINE_DECLARE_DEBUG_CHANNEL(d3d_perf);
29 WINE_DECLARE_DEBUG_CHANNEL(winediag);
31 #define WINED3D_TEXTURE_DYNAMIC_MAP_THRESHOLD 50
33 static const uint32_t wined3d_texture_sysmem_locations = WINED3D_LOCATION_SYSMEM
34 | WINED3D_LOCATION_USER_MEMORY | WINED3D_LOCATION_BUFFER;
35 static const struct wined3d_texture_ops texture_gl_ops;
37 struct wined3d_texture_idx
39 struct wined3d_texture *texture;
40 unsigned int sub_resource_idx;
43 struct wined3d_rect_f
45 float l;
46 float t;
47 float r;
48 float b;
51 static BOOL wined3d_texture_use_pbo(const struct wined3d_texture *texture, const struct wined3d_gl_info *gl_info)
53 if (!gl_info->supported[ARB_PIXEL_BUFFER_OBJECT]
54 || texture->resource.format->conv_byte_count
55 || (texture->flags & (WINED3D_TEXTURE_PIN_SYSMEM | WINED3D_TEXTURE_COND_NP2_EMULATED)))
56 return FALSE;
58 /* Use a PBO for dynamic textures and read-only staging textures. */
59 return (!(texture->resource.access & WINED3D_RESOURCE_ACCESS_CPU)
60 && texture->resource.usage & WINED3DUSAGE_DYNAMIC)
61 || texture->resource.access == (WINED3D_RESOURCE_ACCESS_CPU | WINED3D_RESOURCE_ACCESS_MAP_R);
64 static BOOL wined3d_texture_use_immutable_storage(const struct wined3d_texture *texture,
65 const struct wined3d_gl_info *gl_info)
67 /* We don't expect to create texture views for textures with height-scaled formats.
68 * Besides, ARB_texture_storage doesn't allow specifying exact sizes for all levels. */
69 return gl_info->supported[ARB_TEXTURE_STORAGE]
70 && !(texture->resource.format_flags & WINED3DFMT_FLAG_HEIGHT_SCALE);
73 /* Front buffer coordinates are always full screen coordinates, but our GL
74 * drawable is limited to the window's client area. The sysmem and texture
75 * copies do have the full screen size. Note that GL has a bottom-left
76 * origin, while D3D has a top-left origin. */
77 void wined3d_texture_translate_drawable_coords(const struct wined3d_texture *texture, HWND window, RECT *rect)
79 unsigned int drawable_height;
80 POINT offset = {0, 0};
81 RECT windowsize;
83 if (!texture->swapchain)
84 return;
86 if (texture == texture->swapchain->front_buffer)
88 ScreenToClient(window, &offset);
89 OffsetRect(rect, offset.x, offset.y);
92 GetClientRect(window, &windowsize);
93 drawable_height = windowsize.bottom - windowsize.top;
95 rect->top = drawable_height - rect->top;
96 rect->bottom = drawable_height - rect->bottom;
99 GLenum wined3d_texture_get_gl_buffer(const struct wined3d_texture *texture)
101 const struct wined3d_swapchain *swapchain = texture->swapchain;
103 TRACE("texture %p.\n", texture);
105 if (!swapchain)
107 ERR("Texture %p is not part of a swapchain.\n", texture);
108 return GL_NONE;
111 if (texture == swapchain->front_buffer)
113 TRACE("Returning GL_FRONT.\n");
114 return GL_FRONT;
117 if (texture == swapchain->back_buffers[0])
119 TRACE("Returning GL_BACK.\n");
120 return GL_BACK;
123 FIXME("Higher back buffer, returning GL_BACK.\n");
124 return GL_BACK;
127 static DWORD wined3d_resource_access_from_location(DWORD location)
129 switch (location)
131 case WINED3D_LOCATION_DISCARDED:
132 return 0;
134 case WINED3D_LOCATION_SYSMEM:
135 case WINED3D_LOCATION_USER_MEMORY:
136 return WINED3D_RESOURCE_ACCESS_CPU;
138 case WINED3D_LOCATION_BUFFER:
139 case WINED3D_LOCATION_DRAWABLE:
140 case WINED3D_LOCATION_TEXTURE_RGB:
141 case WINED3D_LOCATION_TEXTURE_SRGB:
142 case WINED3D_LOCATION_RB_MULTISAMPLE:
143 case WINED3D_LOCATION_RB_RESOLVED:
144 return WINED3D_RESOURCE_ACCESS_GPU;
146 default:
147 FIXME("Unhandled location %#x.\n", location);
148 return 0;
152 static inline void cube_coords_float(const RECT *r, UINT w, UINT h, struct wined3d_rect_f *f)
154 f->l = ((r->left * 2.0f) / w) - 1.0f;
155 f->t = ((r->top * 2.0f) / h) - 1.0f;
156 f->r = ((r->right * 2.0f) / w) - 1.0f;
157 f->b = ((r->bottom * 2.0f) / h) - 1.0f;
160 void texture2d_get_blt_info(const struct wined3d_texture_gl *texture_gl,
161 unsigned int sub_resource_idx, const RECT *rect, struct wined3d_blt_info *info)
163 struct wined3d_vec3 *coords = info->texcoords;
164 struct wined3d_rect_f f;
165 unsigned int level;
166 GLenum target;
167 GLsizei w, h;
169 level = sub_resource_idx % texture_gl->t.level_count;
170 w = wined3d_texture_get_level_pow2_width(&texture_gl->t, level);
171 h = wined3d_texture_get_level_pow2_height(&texture_gl->t, level);
172 target = wined3d_texture_gl_get_sub_resource_target(texture_gl, sub_resource_idx);
174 switch (target)
176 default:
177 FIXME("Unsupported texture target %#x.\n", target);
178 /* Fall back to GL_TEXTURE_2D */
179 case GL_TEXTURE_2D:
180 info->bind_target = GL_TEXTURE_2D;
181 coords[0].x = (float)rect->left / w;
182 coords[0].y = (float)rect->top / h;
183 coords[0].z = 0.0f;
185 coords[1].x = (float)rect->right / w;
186 coords[1].y = (float)rect->top / h;
187 coords[1].z = 0.0f;
189 coords[2].x = (float)rect->left / w;
190 coords[2].y = (float)rect->bottom / h;
191 coords[2].z = 0.0f;
193 coords[3].x = (float)rect->right / w;
194 coords[3].y = (float)rect->bottom / h;
195 coords[3].z = 0.0f;
196 break;
198 case GL_TEXTURE_RECTANGLE_ARB:
199 info->bind_target = GL_TEXTURE_RECTANGLE_ARB;
200 coords[0].x = rect->left; coords[0].y = rect->top; coords[0].z = 0.0f;
201 coords[1].x = rect->right; coords[1].y = rect->top; coords[1].z = 0.0f;
202 coords[2].x = rect->left; coords[2].y = rect->bottom; coords[2].z = 0.0f;
203 coords[3].x = rect->right; coords[3].y = rect->bottom; coords[3].z = 0.0f;
204 break;
206 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
207 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
208 cube_coords_float(rect, w, h, &f);
210 coords[0].x = 1.0f; coords[0].y = -f.t; coords[0].z = -f.l;
211 coords[1].x = 1.0f; coords[1].y = -f.t; coords[1].z = -f.r;
212 coords[2].x = 1.0f; coords[2].y = -f.b; coords[2].z = -f.l;
213 coords[3].x = 1.0f; coords[3].y = -f.b; coords[3].z = -f.r;
214 break;
216 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
217 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
218 cube_coords_float(rect, w, h, &f);
220 coords[0].x = -1.0f; coords[0].y = -f.t; coords[0].z = f.l;
221 coords[1].x = -1.0f; coords[1].y = -f.t; coords[1].z = f.r;
222 coords[2].x = -1.0f; coords[2].y = -f.b; coords[2].z = f.l;
223 coords[3].x = -1.0f; coords[3].y = -f.b; coords[3].z = f.r;
224 break;
226 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
227 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
228 cube_coords_float(rect, w, h, &f);
230 coords[0].x = f.l; coords[0].y = 1.0f; coords[0].z = f.t;
231 coords[1].x = f.r; coords[1].y = 1.0f; coords[1].z = f.t;
232 coords[2].x = f.l; coords[2].y = 1.0f; coords[2].z = f.b;
233 coords[3].x = f.r; coords[3].y = 1.0f; coords[3].z = f.b;
234 break;
236 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
237 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
238 cube_coords_float(rect, w, h, &f);
240 coords[0].x = f.l; coords[0].y = -1.0f; coords[0].z = -f.t;
241 coords[1].x = f.r; coords[1].y = -1.0f; coords[1].z = -f.t;
242 coords[2].x = f.l; coords[2].y = -1.0f; coords[2].z = -f.b;
243 coords[3].x = f.r; coords[3].y = -1.0f; coords[3].z = -f.b;
244 break;
246 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
247 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
248 cube_coords_float(rect, w, h, &f);
250 coords[0].x = f.l; coords[0].y = -f.t; coords[0].z = 1.0f;
251 coords[1].x = f.r; coords[1].y = -f.t; coords[1].z = 1.0f;
252 coords[2].x = f.l; coords[2].y = -f.b; coords[2].z = 1.0f;
253 coords[3].x = f.r; coords[3].y = -f.b; coords[3].z = 1.0f;
254 break;
256 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
257 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
258 cube_coords_float(rect, w, h, &f);
260 coords[0].x = -f.l; coords[0].y = -f.t; coords[0].z = -1.0f;
261 coords[1].x = -f.r; coords[1].y = -f.t; coords[1].z = -1.0f;
262 coords[2].x = -f.l; coords[2].y = -f.b; coords[2].z = -1.0f;
263 coords[3].x = -f.r; coords[3].y = -f.b; coords[3].z = -1.0f;
264 break;
268 static void wined3d_texture_evict_sysmem(struct wined3d_texture *texture)
270 struct wined3d_texture_sub_resource *sub_resource;
271 unsigned int i, sub_count;
273 if (texture->flags & (WINED3D_TEXTURE_CONVERTED | WINED3D_TEXTURE_PIN_SYSMEM)
274 || texture->download_count > WINED3D_TEXTURE_DYNAMIC_MAP_THRESHOLD)
276 TRACE("Not evicting system memory for texture %p.\n", texture);
277 return;
280 TRACE("Evicting system memory for texture %p.\n", texture);
282 sub_count = texture->level_count * texture->layer_count;
283 for (i = 0; i < sub_count; ++i)
285 sub_resource = &texture->sub_resources[i];
286 if (sub_resource->locations == WINED3D_LOCATION_SYSMEM)
287 ERR("WINED3D_LOCATION_SYSMEM is the only location for sub-resource %u of texture %p.\n",
288 i, texture);
289 sub_resource->locations &= ~WINED3D_LOCATION_SYSMEM;
291 wined3d_resource_free_sysmem(&texture->resource);
294 void wined3d_texture_validate_location(struct wined3d_texture *texture,
295 unsigned int sub_resource_idx, DWORD location)
297 struct wined3d_texture_sub_resource *sub_resource;
298 DWORD previous_locations;
300 TRACE("texture %p, sub_resource_idx %u, location %s.\n",
301 texture, sub_resource_idx, wined3d_debug_location(location));
303 sub_resource = &texture->sub_resources[sub_resource_idx];
304 previous_locations = sub_resource->locations;
305 sub_resource->locations |= location;
306 if (previous_locations == WINED3D_LOCATION_SYSMEM && location != WINED3D_LOCATION_SYSMEM
307 && !--texture->sysmem_count)
308 wined3d_texture_evict_sysmem(texture);
310 TRACE("New locations flags are %s.\n", wined3d_debug_location(sub_resource->locations));
313 static void wined3d_texture_set_dirty(struct wined3d_texture *texture)
315 texture->flags &= ~(WINED3D_TEXTURE_RGB_VALID | WINED3D_TEXTURE_SRGB_VALID);
318 void wined3d_texture_invalidate_location(struct wined3d_texture *texture,
319 unsigned int sub_resource_idx, DWORD location)
321 struct wined3d_texture_sub_resource *sub_resource;
322 DWORD previous_locations;
324 TRACE("texture %p, sub_resource_idx %u, location %s.\n",
325 texture, sub_resource_idx, wined3d_debug_location(location));
327 if (location & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB))
328 wined3d_texture_set_dirty(texture);
330 sub_resource = &texture->sub_resources[sub_resource_idx];
331 previous_locations = sub_resource->locations;
332 sub_resource->locations &= ~location;
333 if (previous_locations != WINED3D_LOCATION_SYSMEM && sub_resource->locations == WINED3D_LOCATION_SYSMEM)
334 ++texture->sysmem_count;
336 TRACE("New locations flags are %s.\n", wined3d_debug_location(sub_resource->locations));
338 if (!sub_resource->locations)
339 ERR("Sub-resource %u of texture %p does not have any up to date location.\n",
340 sub_resource_idx, texture);
343 void wined3d_texture_clear_dirty_regions(struct wined3d_texture *texture)
345 unsigned int i;
347 TRACE("texture %p\n", texture);
349 if (!texture->dirty_regions)
350 return;
352 for (i = 0; i < texture->layer_count; ++i)
354 texture->dirty_regions[i].box_count = 0;
358 static BOOL wined3d_texture_copy_sysmem_location(struct wined3d_texture *texture,
359 unsigned int sub_resource_idx, struct wined3d_context *context, DWORD location)
361 unsigned int size = texture->sub_resources[sub_resource_idx].size;
362 struct wined3d_device *device = texture->resource.device;
363 const struct wined3d_gl_info *gl_info;
364 struct wined3d_bo_address dst, src;
366 if (!wined3d_texture_prepare_location(texture, sub_resource_idx, context, location))
367 return FALSE;
369 wined3d_texture_get_memory(texture, sub_resource_idx, &dst, location);
370 wined3d_texture_get_memory(texture, sub_resource_idx, &src,
371 texture->sub_resources[sub_resource_idx].locations);
373 if (dst.buffer_object)
375 context = context_acquire(device, NULL, 0);
376 gl_info = wined3d_context_gl(context)->gl_info;
377 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, dst.buffer_object));
378 GL_EXTCALL(glBufferSubData(GL_PIXEL_UNPACK_BUFFER, 0, size, src.addr));
379 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));
380 checkGLcall("PBO upload");
381 context_release(context);
382 return TRUE;
385 if (src.buffer_object)
387 context = context_acquire(device, NULL, 0);
388 gl_info = wined3d_context_gl(context)->gl_info;
389 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, src.buffer_object));
390 GL_EXTCALL(glGetBufferSubData(GL_PIXEL_PACK_BUFFER, 0, size, dst.addr));
391 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
392 checkGLcall("PBO download");
393 context_release(context);
394 return TRUE;
397 memcpy(dst.addr, src.addr, size);
398 return TRUE;
401 /* Context activation is done by the caller. Context may be NULL in
402 * WINED3D_NO3D mode. */
403 BOOL wined3d_texture_load_location(struct wined3d_texture *texture,
404 unsigned int sub_resource_idx, struct wined3d_context *context, DWORD location)
406 DWORD current = texture->sub_resources[sub_resource_idx].locations;
407 BOOL ret;
409 TRACE("texture %p, sub_resource_idx %u, context %p, location %s.\n",
410 texture, sub_resource_idx, context, wined3d_debug_location(location));
412 TRACE("Current resource location %s.\n", wined3d_debug_location(current));
414 if (current & location)
416 TRACE("Location %s is already up to date.\n", wined3d_debug_location(location));
417 return TRUE;
420 if (WARN_ON(d3d))
422 DWORD required_access = wined3d_resource_access_from_location(location);
423 if ((texture->resource.access & required_access) != required_access)
424 WARN("Operation requires %#x access, but texture only has %#x.\n",
425 required_access, texture->resource.access);
428 if (current & WINED3D_LOCATION_DISCARDED)
430 TRACE("Sub-resource previously discarded, nothing to do.\n");
431 if (!wined3d_texture_prepare_location(texture, sub_resource_idx, context, location))
432 return FALSE;
433 wined3d_texture_validate_location(texture, sub_resource_idx, location);
434 wined3d_texture_invalidate_location(texture, sub_resource_idx, WINED3D_LOCATION_DISCARDED);
435 return TRUE;
438 if (!current)
440 ERR("Sub-resource %u of texture %p does not have any up to date location.\n",
441 sub_resource_idx, texture);
442 wined3d_texture_validate_location(texture, sub_resource_idx, WINED3D_LOCATION_DISCARDED);
443 return wined3d_texture_load_location(texture, sub_resource_idx, context, location);
446 if ((location & wined3d_texture_sysmem_locations) && (current & wined3d_texture_sysmem_locations))
447 ret = wined3d_texture_copy_sysmem_location(texture, sub_resource_idx, context, location);
448 else
449 ret = texture->texture_ops->texture_load_location(texture, sub_resource_idx, context, location);
451 if (ret)
452 wined3d_texture_validate_location(texture, sub_resource_idx, location);
454 return ret;
457 void wined3d_texture_get_memory(struct wined3d_texture *texture, unsigned int sub_resource_idx,
458 struct wined3d_bo_address *data, DWORD locations)
460 struct wined3d_texture_sub_resource *sub_resource;
462 TRACE("texture %p, sub_resource_idx %u, data %p, locations %s.\n",
463 texture, sub_resource_idx, data, wined3d_debug_location(locations));
465 sub_resource = &texture->sub_resources[sub_resource_idx];
466 if (locations & WINED3D_LOCATION_BUFFER)
468 data->addr = NULL;
469 data->buffer_object = sub_resource->buffer_object;
470 return;
472 if (locations & WINED3D_LOCATION_USER_MEMORY)
474 data->addr = texture->user_memory;
475 data->buffer_object = 0;
476 return;
478 if (locations & WINED3D_LOCATION_SYSMEM)
480 data->addr = texture->resource.heap_memory;
481 data->addr += sub_resource->offset;
482 data->buffer_object = 0;
483 return;
486 ERR("Unexpected locations %s.\n", wined3d_debug_location(locations));
487 data->addr = NULL;
488 data->buffer_object = 0;
491 /* Context activation is done by the caller. */
492 static void wined3d_texture_remove_buffer_object(struct wined3d_texture *texture,
493 unsigned int sub_resource_idx, const struct wined3d_gl_info *gl_info)
495 uintptr_t *buffer_object = &texture->sub_resources[sub_resource_idx].buffer_object;
496 GLuint bo;
498 bo = *buffer_object;
499 GL_EXTCALL(glDeleteBuffers(1, &bo));
500 checkGLcall("glDeleteBuffers");
502 TRACE("Deleted buffer object %u for texture %p, sub-resource %u.\n",
503 bo, texture, sub_resource_idx);
505 wined3d_texture_invalidate_location(texture, sub_resource_idx, WINED3D_LOCATION_BUFFER);
506 *buffer_object = 0;
509 static void wined3d_texture_update_map_binding(struct wined3d_texture *texture)
511 unsigned int sub_count = texture->level_count * texture->layer_count;
512 struct wined3d_device *device = texture->resource.device;
513 DWORD map_binding = texture->update_map_binding;
514 struct wined3d_context *context = NULL;
515 unsigned int i;
517 if (device->d3d_initialized)
518 context = context_acquire(device, NULL, 0);
520 for (i = 0; i < sub_count; ++i)
522 if (texture->sub_resources[i].locations == texture->resource.map_binding
523 && !wined3d_texture_load_location(texture, i, context, map_binding))
524 ERR("Failed to load location %s.\n", wined3d_debug_location(map_binding));
525 if (texture->resource.map_binding == WINED3D_LOCATION_BUFFER)
526 wined3d_texture_remove_buffer_object(texture, i, wined3d_context_gl(context)->gl_info);
529 if (context)
530 context_release(context);
532 texture->resource.map_binding = map_binding;
533 texture->update_map_binding = 0;
536 void wined3d_texture_set_map_binding(struct wined3d_texture *texture, DWORD map_binding)
538 texture->update_map_binding = map_binding;
539 if (!texture->resource.map_count)
540 wined3d_texture_update_map_binding(texture);
543 /* A GL context is provided by the caller */
544 static void gltexture_delete(struct wined3d_device *device, const struct wined3d_gl_info *gl_info,
545 struct gl_texture *tex)
547 context_gl_resource_released(device, tex->name, FALSE);
548 gl_info->gl_ops.gl.p_glDeleteTextures(1, &tex->name);
549 tex->name = 0;
552 /* Context activation is done by the caller. */
553 /* The caller is responsible for binding the correct texture. */
554 static void wined3d_texture_gl_allocate_mutable_storage(struct wined3d_texture_gl *texture_gl,
555 GLenum gl_internal_format, const struct wined3d_format_gl *format,
556 const struct wined3d_gl_info *gl_info)
558 unsigned int level, level_count, layer, layer_count;
559 GLsizei width, height, depth;
560 GLenum target;
562 level_count = texture_gl->t.level_count;
563 if (texture_gl->target == GL_TEXTURE_1D_ARRAY || texture_gl->target == GL_TEXTURE_2D_ARRAY)
564 layer_count = 1;
565 else
566 layer_count = texture_gl->t.layer_count;
568 for (layer = 0; layer < layer_count; ++layer)
570 target = wined3d_texture_gl_get_sub_resource_target(texture_gl, layer * level_count);
572 for (level = 0; level < level_count; ++level)
574 width = wined3d_texture_get_level_pow2_width(&texture_gl->t, level);
575 height = wined3d_texture_get_level_pow2_height(&texture_gl->t, level);
576 if (texture_gl->t.resource.format_flags & WINED3DFMT_FLAG_HEIGHT_SCALE)
578 height *= format->f.height_scale.numerator;
579 height /= format->f.height_scale.denominator;
582 TRACE("texture_gl %p, layer %u, level %u, target %#x, width %u, height %u.\n",
583 texture_gl, layer, level, target, width, height);
585 if (target == GL_TEXTURE_3D || target == GL_TEXTURE_2D_ARRAY)
587 depth = wined3d_texture_get_level_depth(&texture_gl->t, level);
588 GL_EXTCALL(glTexImage3D(target, level, gl_internal_format, width, height,
589 target == GL_TEXTURE_2D_ARRAY ? texture_gl->t.layer_count : depth, 0,
590 format->format, format->type, NULL));
591 checkGLcall("glTexImage3D");
593 else if (target == GL_TEXTURE_1D)
595 gl_info->gl_ops.gl.p_glTexImage1D(target, level, gl_internal_format,
596 width, 0, format->format, format->type, NULL);
598 else
600 gl_info->gl_ops.gl.p_glTexImage2D(target, level, gl_internal_format, width,
601 target == GL_TEXTURE_1D_ARRAY ? texture_gl->t.layer_count : height, 0,
602 format->format, format->type, NULL);
603 checkGLcall("glTexImage2D");
609 /* Context activation is done by the caller. */
610 /* The caller is responsible for binding the correct texture. */
611 static void wined3d_texture_gl_allocate_immutable_storage(struct wined3d_texture_gl *texture_gl,
612 GLenum gl_internal_format, const struct wined3d_gl_info *gl_info)
614 unsigned int samples = wined3d_resource_get_sample_count(&texture_gl->t.resource);
615 GLsizei height = wined3d_texture_get_level_pow2_height(&texture_gl->t, 0);
616 GLsizei width = wined3d_texture_get_level_pow2_width(&texture_gl->t, 0);
617 GLboolean standard_pattern = texture_gl->t.resource.multisample_type != WINED3D_MULTISAMPLE_NON_MASKABLE
618 && texture_gl->t.resource.multisample_quality == WINED3D_STANDARD_MULTISAMPLE_PATTERN;
620 switch (texture_gl->target)
622 case GL_TEXTURE_3D:
623 GL_EXTCALL(glTexStorage3D(texture_gl->target, texture_gl->t.level_count,
624 gl_internal_format, width, height, wined3d_texture_get_level_depth(&texture_gl->t, 0)));
625 break;
626 case GL_TEXTURE_2D_ARRAY:
627 GL_EXTCALL(glTexStorage3D(texture_gl->target, texture_gl->t.level_count,
628 gl_internal_format, width, height, texture_gl->t.layer_count));
629 break;
630 case GL_TEXTURE_2D_MULTISAMPLE:
631 GL_EXTCALL(glTexStorage2DMultisample(texture_gl->target, samples,
632 gl_internal_format, width, height, standard_pattern));
633 break;
634 case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
635 GL_EXTCALL(glTexStorage3DMultisample(texture_gl->target, samples,
636 gl_internal_format, width, height, texture_gl->t.layer_count, standard_pattern));
637 break;
638 case GL_TEXTURE_1D_ARRAY:
639 GL_EXTCALL(glTexStorage2D(texture_gl->target, texture_gl->t.level_count,
640 gl_internal_format, width, texture_gl->t.layer_count));
641 break;
642 case GL_TEXTURE_1D:
643 GL_EXTCALL(glTexStorage1D(texture_gl->target, texture_gl->t.level_count, gl_internal_format, width));
644 break;
645 default:
646 GL_EXTCALL(glTexStorage2D(texture_gl->target, texture_gl->t.level_count,
647 gl_internal_format, width, height));
648 break;
651 checkGLcall("allocate immutable storage");
654 void wined3d_texture_sub_resources_destroyed(struct wined3d_texture *texture)
656 unsigned int sub_count = texture->level_count * texture->layer_count;
657 struct wined3d_texture_sub_resource *sub_resource;
658 unsigned int i;
660 for (i = 0; i < sub_count; ++i)
662 sub_resource = &texture->sub_resources[i];
663 if (sub_resource->parent)
665 TRACE("sub-resource %u.\n", i);
666 sub_resource->parent_ops->wined3d_object_destroyed(sub_resource->parent);
667 sub_resource->parent = NULL;
672 static void wined3d_texture_create_dc(void *object)
674 const struct wined3d_texture_idx *idx = object;
675 struct wined3d_context *context = NULL;
676 unsigned int sub_resource_idx, level;
677 const struct wined3d_format *format;
678 unsigned int row_pitch, slice_pitch;
679 struct wined3d_texture *texture;
680 struct wined3d_dc_info *dc_info;
681 struct wined3d_bo_address data;
682 D3DKMT_CREATEDCFROMMEMORY desc;
683 struct wined3d_device *device;
684 NTSTATUS status;
686 TRACE("texture %p, sub_resource_idx %u.\n", idx->texture, idx->sub_resource_idx);
688 texture = idx->texture;
689 sub_resource_idx = idx->sub_resource_idx;
690 level = sub_resource_idx % texture->level_count;
691 device = texture->resource.device;
693 format = texture->resource.format;
694 if (!format->ddi_format)
696 WARN("Cannot create a DC for format %s.\n", debug_d3dformat(format->id));
697 return;
700 if (!texture->dc_info)
702 unsigned int sub_count = texture->level_count * texture->layer_count;
704 if (!(texture->dc_info = heap_calloc(sub_count, sizeof(*texture->dc_info))))
706 ERR("Failed to allocate DC info.\n");
707 return;
711 if (!(texture->sub_resources[sub_resource_idx].locations & texture->resource.map_binding))
713 context = context_acquire(device, NULL, 0);
714 wined3d_texture_load_location(texture, sub_resource_idx, context, texture->resource.map_binding);
716 wined3d_texture_invalidate_location(texture, sub_resource_idx, ~texture->resource.map_binding);
717 wined3d_texture_get_pitch(texture, level, &row_pitch, &slice_pitch);
718 wined3d_texture_get_memory(texture, sub_resource_idx, &data, texture->resource.map_binding);
719 if (data.buffer_object)
721 if (!context)
722 context = context_acquire(device, NULL, 0);
723 desc.pMemory = wined3d_context_map_bo_address(context, &data,
724 texture->sub_resources[sub_resource_idx].size, 0, WINED3D_MAP_READ | WINED3D_MAP_WRITE);
726 else
728 desc.pMemory = data.addr;
731 if (context)
732 context_release(context);
734 desc.Format = format->ddi_format;
735 desc.Width = wined3d_texture_get_level_width(texture, level);
736 desc.Height = wined3d_texture_get_level_height(texture, level);
737 desc.Pitch = row_pitch;
738 desc.hDeviceDc = CreateCompatibleDC(NULL);
739 desc.pColorTable = NULL;
741 status = D3DKMTCreateDCFromMemory(&desc);
742 DeleteDC(desc.hDeviceDc);
743 if (status)
745 WARN("Failed to create DC, status %#x.\n", status);
746 return;
749 dc_info = &texture->dc_info[sub_resource_idx];
750 dc_info->dc = desc.hDc;
751 dc_info->bitmap = desc.hBitmap;
753 TRACE("Created DC %p, bitmap %p for texture %p, %u.\n", dc_info->dc, dc_info->bitmap, texture, sub_resource_idx);
756 static void wined3d_texture_destroy_dc(void *object)
758 const struct wined3d_texture_idx *idx = object;
759 D3DKMT_DESTROYDCFROMMEMORY destroy_desc;
760 struct wined3d_context *context;
761 struct wined3d_texture *texture;
762 struct wined3d_dc_info *dc_info;
763 struct wined3d_bo_address data;
764 unsigned int sub_resource_idx;
765 struct wined3d_device *device;
766 struct wined3d_range range;
767 NTSTATUS status;
769 texture = idx->texture;
770 sub_resource_idx = idx->sub_resource_idx;
771 device = texture->resource.device;
772 dc_info = &texture->dc_info[sub_resource_idx];
774 if (!dc_info->dc)
776 ERR("Sub-resource {%p, %u} has no DC.\n", texture, sub_resource_idx);
777 return;
780 TRACE("dc %p, bitmap %p.\n", dc_info->dc, dc_info->bitmap);
782 destroy_desc.hDc = dc_info->dc;
783 destroy_desc.hBitmap = dc_info->bitmap;
784 if ((status = D3DKMTDestroyDCFromMemory(&destroy_desc)))
785 ERR("Failed to destroy dc, status %#x.\n", status);
786 dc_info->dc = NULL;
787 dc_info->bitmap = NULL;
789 wined3d_texture_get_memory(texture, sub_resource_idx, &data, texture->resource.map_binding);
790 if (data.buffer_object)
792 context = context_acquire(device, NULL, 0);
793 range.offset = 0;
794 range.size = texture->sub_resources[sub_resource_idx].size;
795 wined3d_context_unmap_bo_address(context, &data, 0, 1, &range);
796 context_release(context);
800 void wined3d_texture_set_swapchain(struct wined3d_texture *texture, struct wined3d_swapchain *swapchain)
802 texture->swapchain = swapchain;
803 wined3d_resource_update_draw_binding(&texture->resource);
806 void wined3d_gl_texture_swizzle_from_color_fixup(GLint swizzle[4], struct color_fixup_desc fixup)
808 static const GLenum swizzle_source[] =
810 GL_ZERO, /* CHANNEL_SOURCE_ZERO */
811 GL_ONE, /* CHANNEL_SOURCE_ONE */
812 GL_RED, /* CHANNEL_SOURCE_X */
813 GL_GREEN, /* CHANNEL_SOURCE_Y */
814 GL_BLUE, /* CHANNEL_SOURCE_Z */
815 GL_ALPHA, /* CHANNEL_SOURCE_W */
818 swizzle[0] = swizzle_source[fixup.x_source];
819 swizzle[1] = swizzle_source[fixup.y_source];
820 swizzle[2] = swizzle_source[fixup.z_source];
821 swizzle[3] = swizzle_source[fixup.w_source];
824 /* Context activation is done by the caller. */
825 void wined3d_texture_gl_bind(struct wined3d_texture_gl *texture_gl,
826 struct wined3d_context_gl *context_gl, BOOL srgb)
828 const struct wined3d_format *format = texture_gl->t.resource.format;
829 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
830 const struct color_fixup_desc fixup = format->color_fixup;
831 struct gl_texture *gl_tex;
832 GLenum target;
834 TRACE("texture_gl %p, context_gl %p, srgb %#x.\n", texture_gl, context_gl, srgb);
836 if (!needs_separate_srgb_gl_texture(&context_gl->c, &texture_gl->t))
837 srgb = FALSE;
839 /* sRGB mode cache for preload() calls outside drawprim. */
840 if (srgb)
841 texture_gl->t.flags |= WINED3D_TEXTURE_IS_SRGB;
842 else
843 texture_gl->t.flags &= ~WINED3D_TEXTURE_IS_SRGB;
845 gl_tex = wined3d_texture_gl_get_gl_texture(texture_gl, srgb);
846 target = texture_gl->target;
848 if (gl_tex->name)
850 wined3d_context_gl_bind_texture(context_gl, target, gl_tex->name);
851 return;
854 gl_info->gl_ops.gl.p_glGenTextures(1, &gl_tex->name);
855 checkGLcall("glGenTextures");
856 TRACE("Generated texture %d.\n", gl_tex->name);
858 if (!gl_tex->name)
860 ERR("Failed to generate a texture name.\n");
861 return;
864 /* Initialise the state of the texture object to the OpenGL defaults, not
865 * the wined3d defaults. */
866 gl_tex->sampler_desc.address_u = WINED3D_TADDRESS_WRAP;
867 gl_tex->sampler_desc.address_v = WINED3D_TADDRESS_WRAP;
868 gl_tex->sampler_desc.address_w = WINED3D_TADDRESS_WRAP;
869 memset(gl_tex->sampler_desc.border_color, 0, sizeof(gl_tex->sampler_desc.border_color));
870 gl_tex->sampler_desc.mag_filter = WINED3D_TEXF_LINEAR;
871 gl_tex->sampler_desc.min_filter = WINED3D_TEXF_POINT; /* GL_NEAREST_MIPMAP_LINEAR */
872 gl_tex->sampler_desc.mip_filter = WINED3D_TEXF_LINEAR; /* GL_NEAREST_MIPMAP_LINEAR */
873 gl_tex->sampler_desc.lod_bias = 0.0f;
874 gl_tex->sampler_desc.min_lod = -1000.0f;
875 gl_tex->sampler_desc.max_lod = 1000.0f;
876 gl_tex->sampler_desc.max_anisotropy = 1;
877 gl_tex->sampler_desc.compare = FALSE;
878 gl_tex->sampler_desc.comparison_func = WINED3D_CMP_LESSEQUAL;
879 if (gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
880 gl_tex->sampler_desc.srgb_decode = TRUE;
881 else
882 gl_tex->sampler_desc.srgb_decode = srgb;
883 gl_tex->base_level = 0;
884 wined3d_texture_set_dirty(&texture_gl->t);
886 wined3d_context_gl_bind_texture(context_gl, target, gl_tex->name);
888 /* For a new texture we have to set the texture levels after binding the
889 * texture. Beware that texture rectangles do not support mipmapping, but
890 * set the maxmiplevel if we're relying on the partial
891 * GL_ARB_texture_non_power_of_two emulation with texture rectangles.
892 * (I.e., do not care about cond_np2 here, just look for
893 * GL_TEXTURE_RECTANGLE_ARB.) */
894 if (target != GL_TEXTURE_RECTANGLE_ARB)
896 TRACE("Setting GL_TEXTURE_MAX_LEVEL to %u.\n", texture_gl->t.level_count - 1);
897 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, texture_gl->t.level_count - 1);
898 checkGLcall("glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, texture->level_count)");
901 if (target == GL_TEXTURE_CUBE_MAP_ARB)
903 /* Cubemaps are always set to clamp, regardless of the sampler state. */
904 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
905 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
906 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
909 if (texture_gl->t.flags & WINED3D_TEXTURE_COND_NP2)
911 /* Conditinal non power of two textures use a different clamping
912 * default. If we're using the GL_WINE_normalized_texrect partial
913 * driver emulation, we're dealing with a GL_TEXTURE_2D texture which
914 * has the address mode set to repeat - something that prevents us
915 * from hitting the accelerated codepath. Thus manually set the GL
916 * state. The same applies to filtering. Even if the texture has only
917 * one mip level, the default LINEAR_MIPMAP_LINEAR filter causes a SW
918 * fallback on macos. */
919 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
920 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
921 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
922 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
923 checkGLcall("glTexParameteri");
924 gl_tex->sampler_desc.address_u = WINED3D_TADDRESS_CLAMP;
925 gl_tex->sampler_desc.address_v = WINED3D_TADDRESS_CLAMP;
926 gl_tex->sampler_desc.mag_filter = WINED3D_TEXF_POINT;
927 gl_tex->sampler_desc.min_filter = WINED3D_TEXF_POINT;
928 gl_tex->sampler_desc.mip_filter = WINED3D_TEXF_NONE;
931 if (gl_info->supported[WINED3D_GL_LEGACY_CONTEXT] && gl_info->supported[ARB_DEPTH_TEXTURE])
933 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY);
934 checkGLcall("glTexParameteri(GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY)");
937 if (!is_identity_fixup(fixup) && can_use_texture_swizzle(context_gl->c.d3d_info, format))
939 GLint swizzle[4];
941 wined3d_gl_texture_swizzle_from_color_fixup(swizzle, fixup);
942 gl_info->gl_ops.gl.p_glTexParameteriv(target, GL_TEXTURE_SWIZZLE_RGBA, swizzle);
943 checkGLcall("set format swizzle");
947 /* Context activation is done by the caller. */
948 void wined3d_texture_gl_bind_and_dirtify(struct wined3d_texture_gl *texture_gl,
949 struct wined3d_context_gl *context_gl, BOOL srgb)
951 /* We don't need a specific texture unit, but after binding the texture
952 * the current unit is dirty. Read the unit back instead of switching to
953 * 0, this avoids messing around with the state manager's GL states. The
954 * current texture unit should always be a valid one.
956 * To be more specific, this is tricky because we can implicitly be
957 * called from sampler() in state.c. This means we can't touch anything
958 * other than whatever happens to be the currently active texture, or we
959 * would risk marking already applied sampler states dirty again. */
960 if (context_gl->active_texture < ARRAY_SIZE(context_gl->rev_tex_unit_map))
962 unsigned int active_sampler = context_gl->rev_tex_unit_map[context_gl->active_texture];
963 if (active_sampler != WINED3D_UNMAPPED_STAGE)
964 context_invalidate_state(&context_gl->c, STATE_SAMPLER(active_sampler));
966 /* FIXME: Ideally we'd only do this when touching a binding that's used by
967 * a shader. */
968 context_invalidate_compute_state(&context_gl->c, STATE_COMPUTE_SHADER_RESOURCE_BINDING);
969 context_invalidate_state(&context_gl->c, STATE_GRAPHICS_SHADER_RESOURCE_BINDING);
971 wined3d_texture_gl_bind(texture_gl, context_gl, srgb);
974 /* Context activation is done by the caller (state handler). */
975 /* This function relies on the correct texture being bound and loaded. */
976 void wined3d_texture_gl_apply_sampler_desc(struct wined3d_texture_gl *texture_gl,
977 const struct wined3d_sampler_desc *sampler_desc, const struct wined3d_context_gl *context_gl)
979 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
980 GLenum target = texture_gl->target;
981 struct gl_texture *gl_tex;
982 DWORD state;
984 TRACE("texture_gl %p, sampler_desc %p, context_gl %p.\n", texture_gl, sampler_desc, context_gl);
986 gl_tex = wined3d_texture_gl_get_gl_texture(texture_gl, texture_gl->t.flags & WINED3D_TEXTURE_IS_SRGB);
988 state = sampler_desc->address_u;
989 if (state != gl_tex->sampler_desc.address_u)
991 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_S,
992 gl_info->wrap_lookup[state - WINED3D_TADDRESS_WRAP]);
993 gl_tex->sampler_desc.address_u = state;
996 state = sampler_desc->address_v;
997 if (state != gl_tex->sampler_desc.address_v)
999 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_T,
1000 gl_info->wrap_lookup[state - WINED3D_TADDRESS_WRAP]);
1001 gl_tex->sampler_desc.address_v = state;
1004 state = sampler_desc->address_w;
1005 if (state != gl_tex->sampler_desc.address_w)
1007 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_R,
1008 gl_info->wrap_lookup[state - WINED3D_TADDRESS_WRAP]);
1009 gl_tex->sampler_desc.address_w = state;
1012 if (memcmp(gl_tex->sampler_desc.border_color, sampler_desc->border_color,
1013 sizeof(gl_tex->sampler_desc.border_color)))
1015 gl_info->gl_ops.gl.p_glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, &sampler_desc->border_color[0]);
1016 memcpy(gl_tex->sampler_desc.border_color, sampler_desc->border_color,
1017 sizeof(gl_tex->sampler_desc.border_color));
1020 state = sampler_desc->mag_filter;
1021 if (state != gl_tex->sampler_desc.mag_filter)
1023 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MAG_FILTER, wined3d_gl_mag_filter(state));
1024 gl_tex->sampler_desc.mag_filter = state;
1027 if (sampler_desc->min_filter != gl_tex->sampler_desc.min_filter
1028 || sampler_desc->mip_filter != gl_tex->sampler_desc.mip_filter)
1030 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MIN_FILTER,
1031 wined3d_gl_min_mip_filter(sampler_desc->min_filter, sampler_desc->mip_filter));
1032 gl_tex->sampler_desc.min_filter = sampler_desc->min_filter;
1033 gl_tex->sampler_desc.mip_filter = sampler_desc->mip_filter;
1036 state = sampler_desc->max_anisotropy;
1037 if (state != gl_tex->sampler_desc.max_anisotropy)
1039 if (gl_info->supported[ARB_TEXTURE_FILTER_ANISOTROPIC])
1040 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MAX_ANISOTROPY, state);
1041 else
1042 WARN("Anisotropic filtering not supported.\n");
1043 gl_tex->sampler_desc.max_anisotropy = state;
1046 if (!sampler_desc->srgb_decode != !gl_tex->sampler_desc.srgb_decode
1047 && (context_gl->c.d3d_info->wined3d_creation_flags & WINED3D_SRGB_READ_WRITE_CONTROL)
1048 && gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
1050 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_SRGB_DECODE_EXT,
1051 sampler_desc->srgb_decode ? GL_DECODE_EXT : GL_SKIP_DECODE_EXT);
1052 gl_tex->sampler_desc.srgb_decode = sampler_desc->srgb_decode;
1055 if (!sampler_desc->compare != !gl_tex->sampler_desc.compare)
1057 if (sampler_desc->compare)
1058 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
1059 else
1060 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
1061 gl_tex->sampler_desc.compare = sampler_desc->compare;
1064 checkGLcall("Texture parameter application");
1066 if (gl_info->supported[EXT_TEXTURE_LOD_BIAS])
1068 gl_info->gl_ops.gl.p_glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT,
1069 GL_TEXTURE_LOD_BIAS_EXT, sampler_desc->lod_bias);
1070 checkGLcall("glTexEnvf(GL_TEXTURE_LOD_BIAS_EXT, ...)");
1074 ULONG CDECL wined3d_texture_incref(struct wined3d_texture *texture)
1076 ULONG refcount;
1078 TRACE("texture %p, swapchain %p.\n", texture, texture->swapchain);
1080 if (texture->swapchain)
1081 return wined3d_swapchain_incref(texture->swapchain);
1083 refcount = InterlockedIncrement(&texture->resource.ref);
1084 TRACE("%p increasing refcount to %u.\n", texture, refcount);
1086 return refcount;
1089 static void wined3d_texture_destroy_object(void *object)
1091 struct wined3d_texture *texture = object;
1092 struct wined3d_resource *resource;
1093 struct wined3d_dc_info *dc_info;
1094 unsigned int sub_count;
1095 unsigned int i;
1097 TRACE("texture %p.\n", texture);
1099 resource = &texture->resource;
1100 sub_count = texture->level_count * texture->layer_count;
1102 if ((dc_info = texture->dc_info))
1104 for (i = 0; i < sub_count; ++i)
1106 if (dc_info[i].dc)
1108 struct wined3d_texture_idx texture_idx = {texture, i};
1110 wined3d_texture_destroy_dc(&texture_idx);
1113 heap_free(dc_info);
1116 if (texture->overlay_info)
1118 for (i = 0; i < sub_count; ++i)
1120 struct wined3d_overlay_info *info = &texture->overlay_info[i];
1121 struct wined3d_overlay_info *overlay, *cur;
1123 list_remove(&info->entry);
1124 LIST_FOR_EACH_ENTRY_SAFE(overlay, cur, &info->overlays, struct wined3d_overlay_info, entry)
1126 list_remove(&overlay->entry);
1129 heap_free(texture->overlay_info);
1132 if (texture->dirty_regions)
1134 for (i = 0; i < texture->layer_count; ++i)
1136 heap_free(texture->dirty_regions[i].boxes);
1138 heap_free(texture->dirty_regions);
1141 resource->resource_ops->resource_unload(resource);
1144 void wined3d_texture_cleanup(struct wined3d_texture *texture)
1146 wined3d_cs_destroy_object(texture->resource.device->cs, wined3d_texture_destroy_object, texture);
1147 resource_cleanup(&texture->resource);
1150 static void wined3d_texture_cleanup_sync(struct wined3d_texture *texture)
1152 wined3d_texture_sub_resources_destroyed(texture);
1153 wined3d_texture_cleanup(texture);
1154 wined3d_resource_wait_idle(&texture->resource);
1157 ULONG CDECL wined3d_texture_decref(struct wined3d_texture *texture)
1159 ULONG refcount;
1161 TRACE("texture %p, swapchain %p.\n", texture, texture->swapchain);
1163 if (texture->swapchain)
1164 return wined3d_swapchain_decref(texture->swapchain);
1166 refcount = InterlockedDecrement(&texture->resource.ref);
1167 TRACE("%p decreasing refcount to %u.\n", texture, refcount);
1169 if (!refcount)
1171 /* Wait for the texture to become idle if it's using user memory,
1172 * since the application is allowed to free that memory once the
1173 * texture is destroyed. Note that this implies that
1174 * the destroy handler can't access that memory either. */
1175 if (texture->user_memory)
1176 wined3d_resource_wait_idle(&texture->resource);
1177 texture->resource.device->adapter->adapter_ops->adapter_destroy_texture(texture);
1180 return refcount;
1183 struct wined3d_resource * CDECL wined3d_texture_get_resource(struct wined3d_texture *texture)
1185 TRACE("texture %p.\n", texture);
1187 return &texture->resource;
1190 static BOOL color_key_equal(const struct wined3d_color_key *c1, struct wined3d_color_key *c2)
1192 return c1->color_space_low_value == c2->color_space_low_value
1193 && c1->color_space_high_value == c2->color_space_high_value;
1196 /* Context activation is done by the caller */
1197 void wined3d_texture_load(struct wined3d_texture *texture,
1198 struct wined3d_context *context, BOOL srgb)
1200 UINT sub_count = texture->level_count * texture->layer_count;
1201 const struct wined3d_d3d_info *d3d_info = context->d3d_info;
1202 DWORD flag;
1203 UINT i;
1205 TRACE("texture %p, context %p, srgb %#x.\n", texture, context, srgb);
1207 if (!needs_separate_srgb_gl_texture(context, texture))
1208 srgb = FALSE;
1210 if (srgb)
1211 flag = WINED3D_TEXTURE_SRGB_VALID;
1212 else
1213 flag = WINED3D_TEXTURE_RGB_VALID;
1215 if (!d3d_info->shader_color_key
1216 && (!(texture->async.flags & WINED3D_TEXTURE_ASYNC_COLOR_KEY)
1217 != !(texture->async.color_key_flags & WINED3D_CKEY_SRC_BLT)
1218 || (texture->async.flags & WINED3D_TEXTURE_ASYNC_COLOR_KEY
1219 && !color_key_equal(&texture->async.gl_color_key, &texture->async.src_blt_color_key))))
1221 unsigned int sub_count = texture->level_count * texture->layer_count;
1222 unsigned int i;
1224 TRACE("Reloading because of color key value change.\n");
1225 for (i = 0; i < sub_count; i++)
1227 if (!wined3d_texture_load_location(texture, i, context, texture->resource.map_binding))
1228 ERR("Failed to load location %s.\n", wined3d_debug_location(texture->resource.map_binding));
1229 else
1230 wined3d_texture_invalidate_location(texture, i, ~texture->resource.map_binding);
1233 texture->async.gl_color_key = texture->async.src_blt_color_key;
1236 if (texture->flags & flag)
1238 TRACE("Texture %p not dirty, nothing to do.\n", texture);
1239 return;
1242 /* Reload the surfaces if the texture is marked dirty. */
1243 for (i = 0; i < sub_count; ++i)
1245 if (!wined3d_texture_load_location(texture, i, context,
1246 srgb ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB))
1247 ERR("Failed to load location (srgb %#x).\n", srgb);
1249 texture->flags |= flag;
1252 void * CDECL wined3d_texture_get_parent(const struct wined3d_texture *texture)
1254 TRACE("texture %p.\n", texture);
1256 return texture->resource.parent;
1259 HRESULT wined3d_texture_check_box_dimensions(const struct wined3d_texture *texture,
1260 unsigned int level, const struct wined3d_box *box)
1262 const struct wined3d_format *format = texture->resource.format;
1263 unsigned int width_mask, height_mask, width, height, depth;
1265 width = wined3d_texture_get_level_width(texture, level);
1266 height = wined3d_texture_get_level_height(texture, level);
1267 depth = wined3d_texture_get_level_depth(texture, level);
1269 if (box->left >= box->right || box->right > width
1270 || box->top >= box->bottom || box->bottom > height
1271 || box->front >= box->back || box->back > depth)
1273 WARN("Box %s is invalid.\n", debug_box(box));
1274 return WINEDDERR_INVALIDRECT;
1277 if (texture->resource.format_flags & WINED3DFMT_FLAG_BLOCKS)
1279 /* This assumes power of two block sizes, but NPOT block sizes would
1280 * be silly anyway.
1282 * This also assumes that the format's block depth is 1. */
1283 width_mask = format->block_width - 1;
1284 height_mask = format->block_height - 1;
1286 if ((box->left & width_mask) || (box->top & height_mask)
1287 || (box->right & width_mask && box->right != width)
1288 || (box->bottom & height_mask && box->bottom != height))
1290 WARN("Box %s is misaligned for %ux%u blocks.\n",
1291 debug_box(box), format->block_width, format->block_height);
1292 return WINED3DERR_INVALIDCALL;
1296 return WINED3D_OK;
1299 void CDECL wined3d_texture_get_pitch(const struct wined3d_texture *texture,
1300 unsigned int level, unsigned int *row_pitch, unsigned int *slice_pitch)
1302 const struct wined3d_resource *resource = &texture->resource;
1303 unsigned int width = wined3d_texture_get_level_width(texture, level);
1304 unsigned int height = wined3d_texture_get_level_height(texture, level);
1306 if (texture->row_pitch)
1308 *row_pitch = texture->row_pitch;
1309 *slice_pitch = texture->slice_pitch;
1310 return;
1313 wined3d_format_calculate_pitch(resource->format, resource->device->surface_alignment,
1314 width, height, row_pitch, slice_pitch);
1317 DWORD CDECL wined3d_texture_set_lod(struct wined3d_texture *texture, DWORD lod)
1319 struct wined3d_resource *resource;
1320 DWORD old = texture->lod;
1322 TRACE("texture %p, lod %u.\n", texture, lod);
1324 /* The d3d9:texture test shows that SetLOD is ignored on non-managed
1325 * textures. The call always returns 0, and GetLOD always returns 0. */
1326 resource = &texture->resource;
1327 if (!wined3d_resource_access_is_managed(resource->access))
1329 TRACE("Ignoring LOD on texture with resource access %s.\n",
1330 wined3d_debug_resource_access(resource->access));
1331 return 0;
1334 if (lod >= texture->level_count)
1335 lod = texture->level_count - 1;
1337 if (texture->lod != lod)
1339 struct wined3d_device *device = resource->device;
1341 wined3d_resource_wait_idle(resource);
1342 texture->lod = lod;
1344 wined3d_texture_gl(texture)->texture_rgb.base_level = ~0u;
1345 wined3d_texture_gl(texture)->texture_srgb.base_level = ~0u;
1346 if (resource->bind_count)
1347 wined3d_cs_emit_set_sampler_state(device->cs, texture->sampler, WINED3D_SAMP_MAX_MIP_LEVEL,
1348 device->state.sampler_states[texture->sampler][WINED3D_SAMP_MAX_MIP_LEVEL]);
1351 return old;
1354 DWORD CDECL wined3d_texture_get_lod(const struct wined3d_texture *texture)
1356 TRACE("texture %p, returning %u.\n", texture, texture->lod);
1358 return texture->lod;
1361 DWORD CDECL wined3d_texture_get_level_count(const struct wined3d_texture *texture)
1363 TRACE("texture %p, returning %u.\n", texture, texture->level_count);
1365 return texture->level_count;
1368 HRESULT CDECL wined3d_texture_set_color_key(struct wined3d_texture *texture,
1369 DWORD flags, const struct wined3d_color_key *color_key)
1371 struct wined3d_device *device = texture->resource.device;
1372 static const DWORD all_flags = WINED3D_CKEY_DST_BLT | WINED3D_CKEY_DST_OVERLAY
1373 | WINED3D_CKEY_SRC_BLT | WINED3D_CKEY_SRC_OVERLAY;
1375 TRACE("texture %p, flags %#x, color_key %p.\n", texture, flags, color_key);
1377 if (flags & ~all_flags)
1379 WARN("Invalid flags passed, returning WINED3DERR_INVALIDCALL.\n");
1380 return WINED3DERR_INVALIDCALL;
1383 wined3d_cs_emit_set_color_key(device->cs, texture, flags, color_key);
1385 return WINED3D_OK;
1388 /* In D3D the depth stencil dimensions have to be greater than or equal to the
1389 * render target dimensions. With FBOs, the dimensions have to be an exact match. */
1390 /* TODO: We should synchronize the renderbuffer's content with the texture's content. */
1391 /* Context activation is done by the caller. */
1392 void wined3d_texture_gl_set_compatible_renderbuffer(struct wined3d_texture_gl *texture_gl,
1393 struct wined3d_context_gl *context_gl, unsigned int level, const struct wined3d_rendertarget_info *rt)
1395 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
1396 struct wined3d_renderbuffer_entry *entry;
1397 unsigned int src_width, src_height;
1398 unsigned int width, height;
1399 GLuint renderbuffer = 0;
1401 if (gl_info->supported[ARB_FRAMEBUFFER_OBJECT])
1402 return;
1404 if (rt && rt->resource->format->id != WINED3DFMT_NULL)
1406 struct wined3d_texture *rt_texture;
1407 unsigned int rt_level;
1409 if (rt->resource->type == WINED3D_RTYPE_BUFFER)
1411 FIXME("Unsupported resource type %s.\n", debug_d3dresourcetype(rt->resource->type));
1412 return;
1414 rt_texture = wined3d_texture_from_resource(rt->resource);
1415 rt_level = rt->sub_resource_idx % rt_texture->level_count;
1417 width = wined3d_texture_get_level_pow2_width(rt_texture, rt_level);
1418 height = wined3d_texture_get_level_pow2_height(rt_texture, rt_level);
1420 else
1422 width = wined3d_texture_get_level_pow2_width(&texture_gl->t, level);
1423 height = wined3d_texture_get_level_pow2_height(&texture_gl->t, level);
1426 src_width = wined3d_texture_get_level_pow2_width(&texture_gl->t, level);
1427 src_height = wined3d_texture_get_level_pow2_height(&texture_gl->t, level);
1429 /* A depth stencil smaller than the render target is not valid */
1430 if (width > src_width || height > src_height)
1431 return;
1433 /* Remove any renderbuffer set if the sizes match */
1434 if (width == src_width && height == src_height)
1436 texture_gl->current_renderbuffer = NULL;
1437 return;
1440 /* Look if we've already got a renderbuffer of the correct dimensions */
1441 LIST_FOR_EACH_ENTRY(entry, &texture_gl->renderbuffers, struct wined3d_renderbuffer_entry, entry)
1443 if (entry->width == width && entry->height == height)
1445 renderbuffer = entry->id;
1446 texture_gl->current_renderbuffer = entry;
1447 break;
1451 if (!renderbuffer)
1453 const struct wined3d_format_gl *format_gl;
1455 format_gl = wined3d_format_gl(texture_gl->t.resource.format);
1456 gl_info->fbo_ops.glGenRenderbuffers(1, &renderbuffer);
1457 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
1458 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER, format_gl->internal, width, height);
1460 entry = heap_alloc(sizeof(*entry));
1461 entry->width = width;
1462 entry->height = height;
1463 entry->id = renderbuffer;
1464 list_add_head(&texture_gl->renderbuffers, &entry->entry);
1466 texture_gl->current_renderbuffer = entry;
1469 checkGLcall("set compatible renderbuffer");
1472 HRESULT CDECL wined3d_texture_update_desc(struct wined3d_texture *texture, UINT width, UINT height,
1473 enum wined3d_format_id format_id, enum wined3d_multisample_type multisample_type,
1474 UINT multisample_quality, void *mem, UINT pitch)
1476 struct wined3d_texture_sub_resource *sub_resource;
1477 const struct wined3d_d3d_info *d3d_info;
1478 const struct wined3d_gl_info *gl_info;
1479 const struct wined3d_format *format;
1480 const struct wined3d *d3d;
1481 struct wined3d_device *device;
1482 unsigned int resource_size;
1483 DWORD valid_location = 0;
1484 BOOL create_dib = FALSE;
1486 TRACE("texture %p, width %u, height %u, format %s, multisample_type %#x, multisample_quality %u, "
1487 "mem %p, pitch %u.\n",
1488 texture, width, height, debug_d3dformat(format_id), multisample_type, multisample_quality, mem, pitch);
1490 device = texture->resource.device;
1491 d3d = device->wined3d;
1492 gl_info = &device->adapter->gl_info;
1493 d3d_info = &device->adapter->d3d_info;
1494 format = wined3d_get_format(device->adapter, format_id, texture->resource.bind_flags);
1495 resource_size = wined3d_format_calculate_size(format, device->surface_alignment, width, height, 1);
1497 if (!resource_size)
1498 return WINED3DERR_INVALIDCALL;
1500 if (texture->level_count * texture->layer_count > 1)
1502 WARN("Texture has multiple sub-resources, not supported.\n");
1503 return WINED3DERR_INVALIDCALL;
1506 if (texture->resource.type != WINED3D_RTYPE_TEXTURE_2D)
1508 WARN("Not supported on %s.\n", debug_d3dresourcetype(texture->resource.type));
1509 return WINED3DERR_INVALIDCALL;
1512 if (texture->resource.map_count)
1514 WARN("Texture is mapped.\n");
1515 return WINED3DERR_INVALIDCALL;
1518 /* We have no way of supporting a pitch that is not a multiple of the pixel
1519 * byte width short of uploading the texture row-by-row.
1520 * Fortunately that's not an issue since D3D9Ex doesn't allow a custom pitch
1521 * for user-memory textures (it always expects packed data) while DirectDraw
1522 * requires a 4-byte aligned pitch and doesn't support texture formats
1523 * larger than 4 bytes per pixel nor any format using 3 bytes per pixel.
1524 * This check is here to verify that the assumption holds. */
1525 if (pitch % texture->resource.format->byte_count)
1527 WARN("Pitch unsupported, not a multiple of the texture format byte width.\n");
1528 return WINED3DERR_INVALIDCALL;
1531 if (device->d3d_initialized)
1532 wined3d_cs_emit_unload_resource(device->cs, &texture->resource);
1533 wined3d_resource_wait_idle(&texture->resource);
1535 sub_resource = &texture->sub_resources[0];
1536 if (texture->dc_info && texture->dc_info[0].dc)
1538 struct wined3d_texture_idx texture_idx = {texture, 0};
1540 wined3d_cs_destroy_object(device->cs, wined3d_texture_destroy_dc, &texture_idx);
1541 wined3d_cs_finish(device->cs, WINED3D_CS_QUEUE_DEFAULT);
1542 create_dib = TRUE;
1545 wined3d_resource_free_sysmem(&texture->resource);
1547 if ((texture->row_pitch = pitch))
1548 texture->slice_pitch = height * pitch;
1549 else
1550 /* User memory surfaces don't have the regular surface alignment. */
1551 wined3d_format_calculate_pitch(format, 1, width, height,
1552 &texture->row_pitch, &texture->slice_pitch);
1554 texture->resource.format = format;
1555 texture->resource.multisample_type = multisample_type;
1556 texture->resource.multisample_quality = multisample_quality;
1557 texture->resource.width = width;
1558 texture->resource.height = height;
1559 if (!(texture->resource.access & WINED3D_RESOURCE_ACCESS_CPU) && d3d->flags & WINED3D_VIDMEM_ACCOUNTING)
1560 adapter_adjust_memory(device->adapter, (INT64)texture->slice_pitch - texture->resource.size);
1561 texture->resource.size = texture->slice_pitch;
1562 sub_resource->size = texture->slice_pitch;
1563 sub_resource->locations = WINED3D_LOCATION_DISCARDED;
1565 if (texture->texture_ops == &texture_gl_ops)
1567 if (multisample_type && gl_info->supported[ARB_TEXTURE_MULTISAMPLE])
1569 wined3d_texture_gl(texture)->target = GL_TEXTURE_2D_MULTISAMPLE;
1570 texture->flags &= ~WINED3D_TEXTURE_DOWNLOADABLE;
1572 else
1574 wined3d_texture_gl(texture)->target = GL_TEXTURE_2D;
1575 texture->flags |= WINED3D_TEXTURE_DOWNLOADABLE;
1579 if (((width & (width - 1)) || (height & (height - 1))) && !d3d_info->texture_npot
1580 && !d3d_info->texture_npot_conditional)
1582 texture->flags |= WINED3D_TEXTURE_COND_NP2_EMULATED;
1583 texture->pow2_width = texture->pow2_height = 1;
1584 while (texture->pow2_width < width)
1585 texture->pow2_width <<= 1;
1586 while (texture->pow2_height < height)
1587 texture->pow2_height <<= 1;
1589 else
1591 texture->flags &= ~WINED3D_TEXTURE_COND_NP2_EMULATED;
1592 texture->pow2_width = width;
1593 texture->pow2_height = height;
1596 if ((texture->user_memory = mem))
1598 texture->resource.map_binding = WINED3D_LOCATION_USER_MEMORY;
1599 valid_location = WINED3D_LOCATION_USER_MEMORY;
1601 else
1603 if (!wined3d_resource_prepare_sysmem(&texture->resource))
1604 ERR("Failed to allocate resource memory.\n");
1605 valid_location = WINED3D_LOCATION_SYSMEM;
1608 /* The format might be changed to a format that needs conversion.
1609 * If the surface didn't use PBOs previously but could now, don't
1610 * change it - whatever made us not use PBOs might come back, e.g.
1611 * color keys. */
1612 if (texture->resource.map_binding == WINED3D_LOCATION_BUFFER && !wined3d_texture_use_pbo(texture, gl_info))
1613 texture->resource.map_binding = WINED3D_LOCATION_SYSMEM;
1615 wined3d_texture_validate_location(texture, 0, valid_location);
1616 wined3d_texture_invalidate_location(texture, 0, ~valid_location);
1618 if (create_dib)
1620 struct wined3d_texture_idx texture_idx = {texture, 0};
1622 wined3d_cs_init_object(device->cs, wined3d_texture_create_dc, &texture_idx);
1623 wined3d_cs_finish(device->cs, WINED3D_CS_QUEUE_DEFAULT);
1626 return WINED3D_OK;
1629 /* Context activation is done by the caller. */
1630 static void wined3d_texture_prepare_buffer_object(struct wined3d_texture *texture,
1631 unsigned int sub_resource_idx, const struct wined3d_gl_info *gl_info)
1633 struct wined3d_texture_sub_resource *sub_resource;
1634 GLuint bo;
1636 sub_resource = &texture->sub_resources[sub_resource_idx];
1637 if (sub_resource->buffer_object)
1638 return;
1640 GL_EXTCALL(glGenBuffers(1, &bo));
1641 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, bo));
1642 GL_EXTCALL(glBufferData(GL_PIXEL_UNPACK_BUFFER, sub_resource->size, NULL, GL_STREAM_DRAW));
1643 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));
1644 checkGLcall("Create buffer object");
1646 sub_resource->buffer_object = bo;
1647 TRACE("Created buffer object %u for texture %p, sub-resource %u.\n", bo, texture, sub_resource_idx);
1650 static void wined3d_texture_force_reload(struct wined3d_texture *texture)
1652 unsigned int sub_count = texture->level_count * texture->layer_count;
1653 unsigned int i;
1655 texture->flags &= ~(WINED3D_TEXTURE_RGB_ALLOCATED | WINED3D_TEXTURE_SRGB_ALLOCATED
1656 | WINED3D_TEXTURE_CONVERTED);
1657 texture->async.flags &= ~WINED3D_TEXTURE_ASYNC_COLOR_KEY;
1658 for (i = 0; i < sub_count; ++i)
1660 wined3d_texture_invalidate_location(texture, i,
1661 WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB);
1665 /* Context activation is done by the caller. */
1666 void wined3d_texture_gl_prepare_texture(struct wined3d_texture_gl *texture_gl,
1667 struct wined3d_context_gl *context_gl, BOOL srgb)
1669 DWORD alloc_flag = srgb ? WINED3D_TEXTURE_SRGB_ALLOCATED : WINED3D_TEXTURE_RGB_ALLOCATED;
1670 const struct wined3d_d3d_info *d3d_info = context_gl->c.d3d_info;
1671 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
1672 struct wined3d_resource *resource = &texture_gl->t.resource;
1673 const struct wined3d_device *device = resource->device;
1674 const struct wined3d_format *format = resource->format;
1675 const struct wined3d_color_key_conversion *conversion;
1676 const struct wined3d_format_gl *format_gl;
1677 GLenum internal;
1679 TRACE("texture_gl %p, context_gl %p, format %s.\n", texture_gl, context_gl, debug_d3dformat(format->id));
1681 if (!d3d_info->shader_color_key
1682 && !(texture_gl->t.async.flags & WINED3D_TEXTURE_ASYNC_COLOR_KEY)
1683 != !(texture_gl->t.async.color_key_flags & WINED3D_CKEY_SRC_BLT))
1685 wined3d_texture_force_reload(&texture_gl->t);
1687 if (texture_gl->t.async.color_key_flags & WINED3D_CKEY_SRC_BLT)
1688 texture_gl->t.async.flags |= WINED3D_TEXTURE_ASYNC_COLOR_KEY;
1691 if (texture_gl->t.flags & alloc_flag)
1692 return;
1694 if (resource->format_flags & WINED3DFMT_FLAG_DECOMPRESS)
1696 TRACE("WINED3DFMT_FLAG_DECOMPRESS set.\n");
1697 texture_gl->t.flags |= WINED3D_TEXTURE_CONVERTED;
1698 format = wined3d_resource_get_decompress_format(resource);
1700 else if (format->conv_byte_count)
1702 texture_gl->t.flags |= WINED3D_TEXTURE_CONVERTED;
1704 else if ((conversion = wined3d_format_get_color_key_conversion(&texture_gl->t, TRUE)))
1706 texture_gl->t.flags |= WINED3D_TEXTURE_CONVERTED;
1707 format = wined3d_get_format(device->adapter, conversion->dst_format, resource->bind_flags);
1708 TRACE("Using format %s for color key conversion.\n", debug_d3dformat(format->id));
1710 format_gl = wined3d_format_gl(format);
1712 wined3d_texture_gl_bind_and_dirtify(texture_gl, context_gl, srgb);
1714 if (srgb)
1715 internal = format_gl->srgb_internal;
1716 else if (resource->bind_flags & WINED3D_BIND_RENDER_TARGET && wined3d_resource_is_offscreen(resource))
1717 internal = format_gl->rt_internal;
1718 else
1719 internal = format_gl->internal;
1721 if (!internal)
1722 FIXME("No GL internal format for format %s.\n", debug_d3dformat(format->id));
1724 TRACE("internal %#x, format %#x, type %#x.\n", internal, format_gl->format, format_gl->type);
1726 if (wined3d_texture_use_immutable_storage(&texture_gl->t, gl_info))
1727 wined3d_texture_gl_allocate_immutable_storage(texture_gl, internal, gl_info);
1728 else
1729 wined3d_texture_gl_allocate_mutable_storage(texture_gl, internal, format_gl, gl_info);
1730 texture_gl->t.flags |= alloc_flag;
1733 static void wined3d_texture_gl_prepare_rb(struct wined3d_texture_gl *texture_gl,
1734 const struct wined3d_gl_info *gl_info, BOOL multisample)
1736 const struct wined3d_format_gl *format_gl;
1738 format_gl = wined3d_format_gl(texture_gl->t.resource.format);
1739 if (multisample)
1741 DWORD samples;
1743 if (texture_gl->rb_multisample)
1744 return;
1746 samples = wined3d_resource_get_sample_count(&texture_gl->t.resource);
1748 gl_info->fbo_ops.glGenRenderbuffers(1, &texture_gl->rb_multisample);
1749 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, texture_gl->rb_multisample);
1750 gl_info->fbo_ops.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,
1751 format_gl->internal, texture_gl->t.resource.width, texture_gl->t.resource.height);
1752 checkGLcall("glRenderbufferStorageMultisample()");
1753 TRACE("Created multisample rb %u.\n", texture_gl->rb_multisample);
1755 else
1757 if (texture_gl->rb_resolved)
1758 return;
1760 gl_info->fbo_ops.glGenRenderbuffers(1, &texture_gl->rb_resolved);
1761 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, texture_gl->rb_resolved);
1762 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER, format_gl->internal,
1763 texture_gl->t.resource.width, texture_gl->t.resource.height);
1764 checkGLcall("glRenderbufferStorage()");
1765 TRACE("Created resolved rb %u.\n", texture_gl->rb_resolved);
1769 BOOL wined3d_texture_prepare_location(struct wined3d_texture *texture,
1770 unsigned int sub_resource_idx, struct wined3d_context *context, unsigned int location)
1772 return texture->texture_ops->texture_prepare_location(texture, sub_resource_idx, context, location);
1775 static void wined3d_texture_unload_location(struct wined3d_texture *texture,
1776 struct wined3d_context *context, unsigned int location)
1778 texture->texture_ops->texture_unload_location(texture, context, location);
1781 static struct wined3d_texture_sub_resource *wined3d_texture_get_sub_resource(struct wined3d_texture *texture,
1782 unsigned int sub_resource_idx)
1784 UINT sub_count = texture->level_count * texture->layer_count;
1786 TRACE("texture %p, sub_resource_idx %u.\n", texture, sub_resource_idx);
1788 if (sub_resource_idx >= sub_count)
1790 WARN("sub_resource_idx %u >= sub_count %u.\n", sub_resource_idx, sub_count);
1791 return NULL;
1794 return &texture->sub_resources[sub_resource_idx];
1797 static void wined3d_texture_dirty_region_add(struct wined3d_texture *texture,
1798 unsigned int layer, const struct wined3d_box *box)
1800 struct wined3d_dirty_regions *regions;
1801 unsigned int count;
1803 if (!texture->dirty_regions)
1804 return;
1806 regions = &texture->dirty_regions[layer];
1807 count = regions->box_count + 1;
1808 if (count >= WINED3D_MAX_DIRTY_REGION_COUNT || !box
1809 || (!box->left && !box->top && !box->front
1810 && box->right == texture->resource.width
1811 && box->bottom == texture->resource.height
1812 && box->back == texture->resource.depth))
1814 regions->box_count = WINED3D_MAX_DIRTY_REGION_COUNT;
1815 return;
1818 if (!wined3d_array_reserve((void **)&regions->boxes, &regions->boxes_size, count, sizeof(*regions->boxes)))
1820 WARN("Failed to grow boxes array, marking entire texture dirty.\n");
1821 regions->box_count = WINED3D_MAX_DIRTY_REGION_COUNT;
1822 return;
1825 regions->boxes[regions->box_count++] = *box;
1828 HRESULT CDECL wined3d_texture_add_dirty_region(struct wined3d_texture *texture,
1829 UINT layer, const struct wined3d_box *dirty_region)
1831 TRACE("texture %p, layer %u, dirty_region %s.\n", texture, layer, debug_box(dirty_region));
1833 if (layer >= texture->layer_count)
1835 WARN("Invalid layer %u specified.\n", layer);
1836 return WINED3DERR_INVALIDCALL;
1839 if (dirty_region && FAILED(wined3d_texture_check_box_dimensions(texture, 0, dirty_region)))
1841 WARN("Invalid dirty_region %s specified.\n", debug_box(dirty_region));
1842 return WINED3DERR_INVALIDCALL;
1845 wined3d_texture_dirty_region_add(texture, layer, dirty_region);
1846 wined3d_cs_emit_add_dirty_texture_region(texture->resource.device->cs, texture, layer);
1848 return WINED3D_OK;
1851 static void wined3d_texture_gl_upload_bo(const struct wined3d_format *src_format, GLenum target,
1852 unsigned int level, unsigned int src_row_pitch, unsigned int dst_x, unsigned int dst_y,
1853 unsigned int dst_z, unsigned int update_w, unsigned int update_h, unsigned int update_d,
1854 const BYTE *addr, BOOL srgb, struct wined3d_texture *dst_texture,
1855 const struct wined3d_gl_info *gl_info)
1857 const struct wined3d_format_gl *format_gl = wined3d_format_gl(src_format);
1859 if (src_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_COMPRESSED)
1861 unsigned int dst_row_pitch, dst_slice_pitch;
1862 GLenum internal;
1864 if (srgb)
1865 internal = format_gl->srgb_internal;
1866 else if (dst_texture->resource.bind_flags & WINED3D_BIND_RENDER_TARGET
1867 && wined3d_resource_is_offscreen(&dst_texture->resource))
1868 internal = format_gl->rt_internal;
1869 else
1870 internal = format_gl->internal;
1872 wined3d_format_calculate_pitch(src_format, 1, update_w, update_h, &dst_row_pitch, &dst_slice_pitch);
1874 TRACE("Uploading compressed data, target %#x, level %u, x %u, y %u, z %u, "
1875 "w %u, h %u, d %u, format %#x, image_size %#x, addr %p.\n",
1876 target, level, dst_x, dst_y, dst_z, update_w, update_h,
1877 update_d, internal, dst_slice_pitch, addr);
1879 if (target == GL_TEXTURE_1D)
1881 GL_EXTCALL(glCompressedTexSubImage1D(target, level, dst_x,
1882 update_w, internal, dst_row_pitch, addr));
1884 else if (dst_row_pitch == src_row_pitch)
1886 if (target == GL_TEXTURE_2D_ARRAY || target == GL_TEXTURE_3D)
1888 GL_EXTCALL(glCompressedTexSubImage3D(target, level, dst_x, dst_y, dst_z,
1889 update_w, update_h, update_d, internal, dst_slice_pitch * update_d, addr));
1891 else
1893 GL_EXTCALL(glCompressedTexSubImage2D(target, level, dst_x, dst_y,
1894 update_w, update_h, internal, dst_slice_pitch, addr));
1897 else
1899 unsigned int row_count = (update_h + src_format->block_height - 1) / src_format->block_height;
1900 unsigned int row, y, z;
1902 /* glCompressedTexSubImage2D() ignores pixel store state, so we
1903 * can't use the unpack row length like for glTexSubImage2D. */
1904 for (z = dst_z; z < dst_z + update_d; ++z)
1906 for (row = 0, y = dst_y; row < row_count; ++row)
1908 if (target == GL_TEXTURE_2D_ARRAY || target == GL_TEXTURE_3D)
1910 GL_EXTCALL(glCompressedTexSubImage3D(target, level, dst_x, y, z,
1911 update_w, src_format->block_height, 1, internal, dst_row_pitch, addr));
1913 else
1915 GL_EXTCALL(glCompressedTexSubImage2D(target, level, dst_x, y,
1916 update_w, src_format->block_height, internal, dst_row_pitch, addr));
1919 y += src_format->block_height;
1920 addr += src_row_pitch;
1924 checkGLcall("Upload compressed texture data");
1926 else
1928 unsigned int y, y_count;
1930 TRACE("Uploading data, target %#x, level %u, x %u, y %u, z %u, "
1931 "w %u, h %u, d %u, format %#x, type %#x, addr %p.\n",
1932 target, level, dst_x, dst_y, dst_z, update_w, update_h,
1933 update_d, format_gl->format, format_gl->type, addr);
1935 if (src_row_pitch)
1937 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, src_row_pitch / src_format->byte_count);
1938 y_count = 1;
1940 else
1942 y_count = update_h;
1943 update_h = 1;
1946 for (y = 0; y < y_count; ++y)
1948 if (target == GL_TEXTURE_2D_ARRAY || target == GL_TEXTURE_3D)
1950 GL_EXTCALL(glTexSubImage3D(target, level, dst_x, dst_y + y, dst_z,
1951 update_w, update_h, update_d, format_gl->format, format_gl->type, addr));
1953 else if (target == GL_TEXTURE_1D)
1955 gl_info->gl_ops.gl.p_glTexSubImage1D(target, level, dst_x,
1956 update_w, format_gl->format, format_gl->type, addr);
1958 else
1960 gl_info->gl_ops.gl.p_glTexSubImage2D(target, level, dst_x, dst_y + y,
1961 update_w, update_h, format_gl->format, format_gl->type, addr);
1964 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1965 checkGLcall("Upload texture data");
1969 static const struct d3dfmt_alpha_fixup
1971 enum wined3d_format_id format_id, conv_format_id;
1973 formats_src_alpha_fixup[] =
1975 {WINED3DFMT_B8G8R8X8_UNORM, WINED3DFMT_B8G8R8A8_UNORM},
1976 {WINED3DFMT_B5G5R5X1_UNORM, WINED3DFMT_B5G5R5A1_UNORM},
1977 {WINED3DFMT_B4G4R4X4_UNORM, WINED3DFMT_B4G4R4A4_UNORM},
1980 static enum wined3d_format_id wined3d_get_alpha_fixup_format(enum wined3d_format_id format_id,
1981 const struct wined3d_format *dst_format)
1983 unsigned int i;
1985 if (!(dst_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_COMPRESSED)
1986 && !dst_format->alpha_size)
1987 return WINED3DFMT_UNKNOWN;
1989 for (i = 0; i < ARRAY_SIZE(formats_src_alpha_fixup); ++i)
1991 if (formats_src_alpha_fixup[i].format_id == format_id)
1992 return formats_src_alpha_fixup[i].conv_format_id;
1995 return WINED3DFMT_UNKNOWN;
1998 static void wined3d_fixup_alpha(const struct wined3d_format *format, const uint8_t *src,
1999 unsigned int src_row_pitch, uint8_t *dst, unsigned int dst_row_pitch,
2000 unsigned int width, unsigned int height)
2002 unsigned int byte_count, alpha_mask;
2003 unsigned int x, y;
2005 byte_count = format->byte_count;
2006 alpha_mask = ((1u << format->alpha_size) - 1) << format->alpha_offset;
2008 switch (byte_count)
2010 case 2:
2011 for (y = 0; y < height; ++y)
2013 const uint16_t *src_row = (const uint16_t *)&src[y * src_row_pitch];
2014 uint16_t *dst_row = (uint16_t *)&dst[y * dst_row_pitch];
2016 for (x = 0; x < width; ++x)
2018 dst_row[x] = src_row[x] | alpha_mask;
2021 break;
2023 case 4:
2024 for (y = 0; y < height; ++y)
2026 const uint32_t *src_row = (const uint32_t *)&src[y * src_row_pitch];
2027 uint32_t *dst_row = (uint32_t *)&dst[y * dst_row_pitch];
2029 for (x = 0; x < width; ++x)
2031 dst_row[x] = src_row[x] | alpha_mask;
2034 break;
2036 default:
2037 ERR("Unsupported byte count %u.\n", byte_count);
2038 break;
2042 static void wined3d_texture_gl_upload_data(struct wined3d_context *context,
2043 const struct wined3d_const_bo_address *src_bo_addr, const struct wined3d_format *src_format,
2044 const struct wined3d_box *src_box, unsigned int src_row_pitch, unsigned int src_slice_pitch,
2045 struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, unsigned int dst_location,
2046 unsigned int dst_x, unsigned int dst_y, unsigned int dst_z)
2048 struct wined3d_context_gl *context_gl = wined3d_context_gl(context);
2049 enum wined3d_format_id alpha_fixup_format_id = WINED3DFMT_UNKNOWN;
2050 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
2051 unsigned int update_w = src_box->right - src_box->left;
2052 unsigned int update_h = src_box->bottom - src_box->top;
2053 unsigned int update_d = src_box->back - src_box->front;
2054 struct wined3d_bo_address bo;
2055 unsigned int level;
2056 BOOL srgb = FALSE;
2057 BOOL decompress;
2058 GLenum target;
2060 TRACE("context %p, src_bo_addr %s, src_format %s, src_box %s, src_row_pitch %u, src_slice_pitch %u, "
2061 "dst_texture %p, dst_sub_resource_idx %u, dst_location %s, dst_x %u, dst_y %u, dst_z %u.\n",
2062 context, debug_const_bo_address(src_bo_addr), debug_d3dformat(src_format->id), debug_box(src_box),
2063 src_row_pitch, src_slice_pitch, dst_texture, dst_sub_resource_idx,
2064 wined3d_debug_location(dst_location), dst_x, dst_y, dst_z);
2066 if (dst_location == WINED3D_LOCATION_TEXTURE_SRGB)
2068 srgb = TRUE;
2070 else if (dst_location != WINED3D_LOCATION_TEXTURE_RGB)
2072 FIXME("Unhandled location %s.\n", wined3d_debug_location(dst_location));
2073 return;
2076 wined3d_texture_gl_bind_and_dirtify(wined3d_texture_gl(dst_texture), wined3d_context_gl(context), srgb);
2078 if (dst_texture->sub_resources[dst_sub_resource_idx].map_count)
2080 WARN("Uploading a texture that is currently mapped, setting WINED3D_TEXTURE_PIN_SYSMEM.\n");
2081 dst_texture->flags |= WINED3D_TEXTURE_PIN_SYSMEM;
2084 if (src_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_HEIGHT_SCALE)
2086 update_h *= src_format->height_scale.numerator;
2087 update_h /= src_format->height_scale.denominator;
2090 target = wined3d_texture_gl_get_sub_resource_target(wined3d_texture_gl(dst_texture), dst_sub_resource_idx);
2091 level = dst_sub_resource_idx % dst_texture->level_count;
2093 switch (target)
2095 case GL_TEXTURE_1D_ARRAY:
2096 dst_y = dst_sub_resource_idx / dst_texture->level_count;
2097 update_h = 1;
2098 break;
2099 case GL_TEXTURE_2D_ARRAY:
2100 dst_z = dst_sub_resource_idx / dst_texture->level_count;
2101 update_d = 1;
2102 break;
2103 case GL_TEXTURE_2D_MULTISAMPLE:
2104 case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
2105 FIXME("Not supported for multisample textures.\n");
2106 return;
2109 bo.buffer_object = src_bo_addr->buffer_object;
2110 bo.addr = (BYTE *)src_bo_addr->addr + src_box->front * src_slice_pitch;
2111 if (dst_texture->resource.format_flags & WINED3DFMT_FLAG_BLOCKS)
2113 bo.addr += (src_box->top / src_format->block_height) * src_row_pitch;
2114 bo.addr += (src_box->left / src_format->block_width) * src_format->block_byte_count;
2116 else
2118 bo.addr += src_box->top * src_row_pitch;
2119 bo.addr += src_box->left * src_format->byte_count;
2122 decompress = (dst_texture->resource.format_flags & WINED3DFMT_FLAG_DECOMPRESS)
2123 || (src_format->decompress && src_format->id != dst_texture->resource.format->id);
2125 if (src_format->upload || decompress
2126 || (alpha_fixup_format_id = wined3d_get_alpha_fixup_format(src_format->id,
2127 dst_texture->resource.format)) != WINED3DFMT_UNKNOWN)
2129 const struct wined3d_format *compressed_format = src_format;
2130 unsigned int dst_row_pitch, dst_slice_pitch;
2131 struct wined3d_format_gl f;
2132 void *converted_mem;
2133 unsigned int z;
2134 BYTE *src_mem;
2136 if (decompress)
2138 src_format = wined3d_resource_get_decompress_format(&dst_texture->resource);
2140 else if (alpha_fixup_format_id != WINED3DFMT_UNKNOWN)
2142 src_format = wined3d_get_format(context->device->adapter, alpha_fixup_format_id, 0);
2143 assert(!!src_format);
2145 else
2147 if (dst_texture->resource.format_flags & WINED3DFMT_FLAG_BLOCKS)
2148 ERR("Converting a block-based format.\n");
2150 f = *wined3d_format_gl(src_format);
2151 f.f.byte_count = src_format->conv_byte_count;
2152 src_format = &f.f;
2155 wined3d_format_calculate_pitch(src_format, 1, update_w, update_h, &dst_row_pitch, &dst_slice_pitch);
2157 if (!(converted_mem = heap_alloc(dst_slice_pitch)))
2159 ERR("Failed to allocate upload buffer.\n");
2160 return;
2163 src_mem = wined3d_context_gl_map_bo_address(context_gl, &bo,
2164 src_slice_pitch * update_d, GL_PIXEL_UNPACK_BUFFER, WINED3D_MAP_READ);
2166 for (z = 0; z < update_d; ++z, src_mem += src_slice_pitch)
2168 if (decompress)
2169 compressed_format->decompress(src_mem, converted_mem, src_row_pitch, src_slice_pitch,
2170 dst_row_pitch, dst_slice_pitch, update_w, update_h, 1);
2171 else if (alpha_fixup_format_id != WINED3DFMT_UNKNOWN)
2172 wined3d_fixup_alpha(src_format, src_mem, src_row_pitch, converted_mem, dst_row_pitch,
2173 update_w, update_h);
2174 else
2175 src_format->upload(src_mem, converted_mem, src_row_pitch, src_slice_pitch,
2176 dst_row_pitch, dst_slice_pitch, update_w, update_h, 1);
2178 wined3d_texture_gl_upload_bo(src_format, target, level, dst_row_pitch, dst_x, dst_y,
2179 dst_z + z, update_w, update_h, 1, converted_mem, srgb, dst_texture, gl_info);
2182 wined3d_context_gl_unmap_bo_address(context_gl, &bo, GL_PIXEL_UNPACK_BUFFER, 0, NULL);
2183 heap_free(converted_mem);
2185 else
2187 if (bo.buffer_object)
2189 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, bo.buffer_object));
2190 checkGLcall("glBindBuffer");
2193 wined3d_texture_gl_upload_bo(src_format, target, level, src_row_pitch, dst_x, dst_y,
2194 dst_z, update_w, update_h, update_d, bo.addr, srgb, dst_texture, gl_info);
2196 if (bo.buffer_object)
2198 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));
2199 checkGLcall("glBindBuffer");
2203 if (gl_info->quirks & WINED3D_QUIRK_FBO_TEX_UPDATE)
2205 struct wined3d_device *device = dst_texture->resource.device;
2206 unsigned int i;
2208 for (i = 0; i < device->context_count; ++i)
2210 wined3d_context_gl_texture_update(wined3d_context_gl(device->contexts[i]), wined3d_texture_gl(dst_texture));
2215 static void wined3d_texture_gl_download_data_slow_path(struct wined3d_texture_gl *texture_gl,
2216 unsigned int sub_resource_idx, struct wined3d_context_gl *context_gl, const struct wined3d_bo_address *data)
2218 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
2219 struct wined3d_texture_sub_resource *sub_resource;
2220 unsigned int dst_row_pitch, dst_slice_pitch;
2221 unsigned int src_row_pitch, src_slice_pitch;
2222 const struct wined3d_format_gl *format_gl;
2223 BYTE *temporary_mem = NULL;
2224 unsigned int level;
2225 GLenum target;
2226 void *mem;
2228 format_gl = wined3d_format_gl(texture_gl->t.resource.format);
2230 /* Only support read back of converted P8 textures. */
2231 if (texture_gl->t.flags & WINED3D_TEXTURE_CONVERTED && format_gl->f.id != WINED3DFMT_P8_UINT
2232 && !format_gl->f.download)
2234 ERR("Trying to read back converted texture %p, %u with format %s.\n",
2235 texture_gl, sub_resource_idx, debug_d3dformat(format_gl->f.id));
2236 return;
2239 sub_resource = &texture_gl->t.sub_resources[sub_resource_idx];
2240 target = wined3d_texture_gl_get_sub_resource_target(texture_gl, sub_resource_idx);
2241 level = sub_resource_idx % texture_gl->t.level_count;
2243 if (target == GL_TEXTURE_1D_ARRAY || target == GL_TEXTURE_2D_ARRAY)
2245 if (format_gl->f.download)
2247 FIXME("Reading back converted array texture %p is not supported.\n", texture_gl);
2248 return;
2251 /* NP2 emulation is not allowed on array textures. */
2252 if (texture_gl->t.flags & WINED3D_TEXTURE_COND_NP2_EMULATED)
2253 ERR("Array texture %p uses NP2 emulation.\n", texture_gl);
2255 WARN_(d3d_perf)("Downloading all miplevel layers to get the data for a single sub-resource.\n");
2257 if (!(temporary_mem = heap_calloc(texture_gl->t.layer_count, sub_resource->size)))
2259 ERR("Out of memory.\n");
2260 return;
2264 if (texture_gl->t.flags & WINED3D_TEXTURE_COND_NP2_EMULATED)
2266 if (format_gl->f.download)
2268 FIXME("Reading back converted texture %p with NP2 emulation is not supported.\n", texture_gl);
2269 return;
2272 wined3d_texture_get_pitch(&texture_gl->t, level, &dst_row_pitch, &dst_slice_pitch);
2273 wined3d_format_calculate_pitch(&format_gl->f, texture_gl->t.resource.device->surface_alignment,
2274 wined3d_texture_get_level_pow2_width(&texture_gl->t, level),
2275 wined3d_texture_get_level_pow2_height(&texture_gl->t, level),
2276 &src_row_pitch, &src_slice_pitch);
2277 if (!(temporary_mem = heap_alloc(src_slice_pitch)))
2279 ERR("Out of memory.\n");
2280 return;
2283 if (data->buffer_object)
2284 ERR("NP2 emulated texture uses PBO unexpectedly.\n");
2285 if (texture_gl->t.resource.format_flags & WINED3DFMT_FLAG_COMPRESSED)
2286 ERR("Unexpected compressed format for NP2 emulated texture.\n");
2289 if (format_gl->f.download)
2291 struct wined3d_format f;
2293 if (data->buffer_object)
2294 ERR("Converted texture %p uses PBO unexpectedly.\n", texture_gl);
2296 WARN_(d3d_perf)("Downloading converted texture %p, %u with format %s.\n",
2297 texture_gl, sub_resource_idx, debug_d3dformat(format_gl->f.id));
2299 f = format_gl->f;
2300 f.byte_count = format_gl->f.conv_byte_count;
2301 wined3d_texture_get_pitch(&texture_gl->t, level, &dst_row_pitch, &dst_slice_pitch);
2302 wined3d_format_calculate_pitch(&f, texture_gl->t.resource.device->surface_alignment,
2303 wined3d_texture_get_level_width(&texture_gl->t, level),
2304 wined3d_texture_get_level_height(&texture_gl->t, level),
2305 &src_row_pitch, &src_slice_pitch);
2307 if (!(temporary_mem = heap_alloc(src_slice_pitch)))
2309 ERR("Failed to allocate memory.\n");
2310 return;
2314 if (temporary_mem)
2316 mem = temporary_mem;
2318 else if (data->buffer_object)
2320 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, data->buffer_object));
2321 checkGLcall("glBindBuffer");
2322 mem = data->addr;
2324 else
2326 mem = data->addr;
2329 if (texture_gl->t.resource.format_flags & WINED3DFMT_FLAG_COMPRESSED)
2331 TRACE("Downloading compressed texture %p, %u, level %u, format %#x, type %#x, data %p.\n",
2332 texture_gl, sub_resource_idx, level, format_gl->format, format_gl->type, mem);
2334 GL_EXTCALL(glGetCompressedTexImage(target, level, mem));
2335 checkGLcall("glGetCompressedTexImage");
2337 else
2339 TRACE("Downloading texture %p, %u, level %u, format %#x, type %#x, data %p.\n",
2340 texture_gl, sub_resource_idx, level, format_gl->format, format_gl->type, mem);
2342 gl_info->gl_ops.gl.p_glGetTexImage(target, level, format_gl->format, format_gl->type, mem);
2343 checkGLcall("glGetTexImage");
2346 if (format_gl->f.download)
2348 format_gl->f.download(mem, data->addr, src_row_pitch, src_slice_pitch, dst_row_pitch, dst_slice_pitch,
2349 wined3d_texture_get_level_width(&texture_gl->t, level),
2350 wined3d_texture_get_level_height(&texture_gl->t, level), 1);
2352 else if (texture_gl->t.flags & WINED3D_TEXTURE_COND_NP2_EMULATED)
2354 const BYTE *src_data;
2355 unsigned int h, y;
2356 BYTE *dst_data;
2357 /* Some games (e.g. Warhammer 40,000) don't properly handle texture
2358 * pitches, preventing us from using the texture pitch to box NPOT
2359 * textures. Instead, we repack the texture's CPU copy so that its
2360 * pitch equals bpp * width instead of bpp * pow2width.
2362 * Instead of boxing the texture:
2364 * │<── texture width ──>│ pow2 width ──>│
2365 * ├─────────────────────┼───────────────┼─
2366 * │111111111111111111111│ │ʌ
2367 * │222222222222222222222│ ││
2368 * │333333333333333333333│ padding │texture height
2369 * │444444444444444444444│ ││
2370 * │555555555555555555555│ │v
2371 * ├─────────────────────┘ ├─
2372 * │ │pow2 height
2373 * │ padding padding ││
2374 * │ │v
2375 * └─────────────────────────────────────┴─
2377 * we're repacking the data to the expected texture width
2379 * │<── texture width ──>│ pow2 width ──>│
2380 * ├─────────────────────┴───────────────┼─
2381 * │1111111111111111111112222222222222222│ʌ
2382 * │2222233333333333333333333344444444444││
2383 * │4444444444555555555555555555555 │texture height
2384 * │ ││
2385 * │ padding padding │v
2386 * │ ├─
2387 * │ │pow2 height
2388 * │ padding padding ││
2389 * │ │v
2390 * └─────────────────────────────────────┴─
2392 * == is the same as
2394 * │<── texture width ──>│
2395 * ├─────────────────────┼─
2396 * │111111111111111111111│ʌ
2397 * │222222222222222222222││
2398 * │333333333333333333333│texture height
2399 * │444444444444444444444││
2400 * │555555555555555555555│v
2401 * └─────────────────────┴─
2403 * This also means that any references to surface memory should work
2404 * with the data as if it were a standard texture with a NPOT width
2405 * instead of a texture boxed up to be a power-of-two texture. */
2406 src_data = mem;
2407 dst_data = data->addr;
2408 TRACE("Repacking the surface data from pitch %u to pitch %u.\n", src_row_pitch, dst_row_pitch);
2409 h = wined3d_texture_get_level_height(&texture_gl->t, level);
2410 for (y = 0; y < h; ++y)
2412 memcpy(dst_data, src_data, dst_row_pitch);
2413 src_data += src_row_pitch;
2414 dst_data += dst_row_pitch;
2417 else if (temporary_mem)
2419 unsigned int layer = sub_resource_idx / texture_gl->t.level_count;
2420 void *src_data = temporary_mem + layer * sub_resource->size;
2421 if (data->buffer_object)
2423 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, data->buffer_object));
2424 checkGLcall("glBindBuffer");
2425 GL_EXTCALL(glBufferSubData(GL_PIXEL_PACK_BUFFER, 0, sub_resource->size, src_data));
2426 checkGLcall("glBufferSubData");
2428 else
2430 memcpy(data->addr, src_data, sub_resource->size);
2434 if (data->buffer_object)
2436 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
2437 checkGLcall("glBindBuffer");
2440 heap_free(temporary_mem);
2443 static void wined3d_texture_gl_download_data(struct wined3d_context *context,
2444 struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx, unsigned int src_location,
2445 const struct wined3d_box *src_box, const struct wined3d_bo_address *dst_bo_addr,
2446 const struct wined3d_format *dst_format, unsigned int dst_x, unsigned int dst_y, unsigned int dst_z,
2447 unsigned int dst_row_pitch, unsigned int dst_slice_pitch)
2449 struct wined3d_texture_gl *src_texture_gl = wined3d_texture_gl(src_texture);
2450 struct wined3d_context_gl *context_gl = wined3d_context_gl(context);
2451 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
2452 unsigned int src_level, src_width, src_height, src_depth;
2453 unsigned int src_row_pitch, src_slice_pitch;
2454 const struct wined3d_format_gl *format_gl;
2455 BOOL srgb = FALSE;
2456 GLenum target;
2458 TRACE("context %p, src_texture %p, src_sub_resource_idx %u, src_location %s, src_box %s, dst_bo_addr %s, "
2459 "dst_format %s, dst_x %u, dst_y %u, dst_z %u, dst_row_pitch %u, dst_slice_pitch %u.\n",
2460 context, src_texture, src_sub_resource_idx, wined3d_debug_location(src_location),
2461 debug_box(src_box), debug_bo_address(dst_bo_addr), debug_d3dformat(dst_format->id),
2462 dst_x, dst_y, dst_z, dst_row_pitch, dst_slice_pitch);
2464 if (src_location == WINED3D_LOCATION_TEXTURE_SRGB)
2466 srgb = TRUE;
2468 else if (src_location != WINED3D_LOCATION_TEXTURE_RGB)
2470 FIXME("Unhandled location %s.\n", wined3d_debug_location(src_location));
2471 return;
2474 src_level = src_sub_resource_idx % src_texture->level_count;
2475 src_width = wined3d_texture_get_level_width(src_texture, src_level);
2476 src_height = wined3d_texture_get_level_height(src_texture, src_level);
2477 src_depth = wined3d_texture_get_level_depth(src_texture, src_level);
2478 if (src_box->left || src_box->top || src_box->right != src_width || src_box->bottom != src_height
2479 || src_box->front || src_box->back != src_depth)
2481 FIXME("Unhandled source box %s.\n", debug_box(src_box));
2482 return;
2485 if (dst_x || dst_y || dst_z)
2487 FIXME("Unhandled destination (%u, %u, %u).\n", dst_x, dst_y, dst_z);
2488 return;
2491 if (dst_format->id != src_texture->resource.format->id)
2493 FIXME("Unhandled format conversion (%s -> %s).\n",
2494 debug_d3dformat(src_texture->resource.format->id),
2495 debug_d3dformat(dst_format->id));
2496 return;
2499 wined3d_texture_get_pitch(src_texture, src_level, &src_row_pitch, &src_slice_pitch);
2500 if (src_row_pitch != dst_row_pitch || src_slice_pitch != dst_slice_pitch)
2502 FIXME("Unhandled destination pitches %u/%u (source pitches %u/%u).\n",
2503 dst_row_pitch, dst_slice_pitch, src_row_pitch, src_slice_pitch);
2504 return;
2507 wined3d_texture_gl_bind_and_dirtify(src_texture_gl, context_gl, srgb);
2509 format_gl = wined3d_format_gl(src_texture->resource.format);
2510 target = wined3d_texture_gl_get_sub_resource_target(src_texture_gl, src_sub_resource_idx);
2512 if ((src_texture->resource.type == WINED3D_RTYPE_TEXTURE_2D
2513 && (target == GL_TEXTURE_2D_ARRAY || format_gl->f.conv_byte_count
2514 || src_texture->flags & (WINED3D_TEXTURE_CONVERTED | WINED3D_TEXTURE_COND_NP2_EMULATED)))
2515 || target == GL_TEXTURE_1D_ARRAY)
2517 wined3d_texture_gl_download_data_slow_path(src_texture_gl, src_sub_resource_idx, context_gl, dst_bo_addr);
2518 return;
2521 if (format_gl->f.conv_byte_count)
2523 FIXME("Attempting to download a converted texture, type %s format %s.\n",
2524 debug_d3dresourcetype(src_texture->resource.type),
2525 debug_d3dformat(format_gl->f.id));
2526 return;
2529 if (dst_bo_addr->buffer_object)
2531 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, dst_bo_addr->buffer_object));
2532 checkGLcall("glBindBuffer");
2535 if (src_texture->resource.format_flags & WINED3DFMT_FLAG_COMPRESSED)
2537 TRACE("Downloading compressed texture %p, %u, level %u, format %#x, type %#x, data %p.\n",
2538 src_texture, src_sub_resource_idx, src_level, format_gl->format, format_gl->type, dst_bo_addr->addr);
2540 GL_EXTCALL(glGetCompressedTexImage(target, src_level, dst_bo_addr->addr));
2541 checkGLcall("glGetCompressedTexImage");
2543 else
2545 TRACE("Downloading texture %p, %u, level %u, format %#x, type %#x, data %p.\n",
2546 src_texture, src_sub_resource_idx, src_level, format_gl->format, format_gl->type, dst_bo_addr->addr);
2548 gl_info->gl_ops.gl.p_glGetTexImage(target, src_level, format_gl->format, format_gl->type, dst_bo_addr->addr);
2549 checkGLcall("glGetTexImage");
2552 if (dst_bo_addr->buffer_object)
2554 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
2555 checkGLcall("glBindBuffer");
2559 /* Context activation is done by the caller. */
2560 static BOOL wined3d_texture_gl_load_sysmem(struct wined3d_texture_gl *texture_gl,
2561 unsigned int sub_resource_idx, struct wined3d_context_gl *context_gl, DWORD dst_location)
2563 struct wined3d_texture_sub_resource *sub_resource;
2565 sub_resource = &texture_gl->t.sub_resources[sub_resource_idx];
2567 /* We cannot download data from multisample textures directly. */
2568 if (wined3d_texture_gl_is_multisample_location(texture_gl, WINED3D_LOCATION_TEXTURE_RGB))
2570 wined3d_texture_load_location(&texture_gl->t, sub_resource_idx, &context_gl->c, WINED3D_LOCATION_RB_RESOLVED);
2571 texture2d_read_from_framebuffer(&texture_gl->t, sub_resource_idx, &context_gl->c,
2572 WINED3D_LOCATION_RB_RESOLVED, dst_location);
2573 return TRUE;
2576 if (sub_resource->locations & (WINED3D_LOCATION_RB_MULTISAMPLE | WINED3D_LOCATION_RB_RESOLVED))
2577 wined3d_texture_load_location(&texture_gl->t, sub_resource_idx, &context_gl->c, WINED3D_LOCATION_TEXTURE_RGB);
2579 /* Download the sub-resource to system memory. */
2580 if (sub_resource->locations & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB))
2582 unsigned int row_pitch, slice_pitch, level;
2583 struct wined3d_bo_address data;
2584 struct wined3d_box src_box;
2585 unsigned int src_location;
2587 level = sub_resource_idx % texture_gl->t.level_count;
2588 wined3d_texture_get_memory(&texture_gl->t, sub_resource_idx, &data, dst_location);
2589 src_location = sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB
2590 ? WINED3D_LOCATION_TEXTURE_RGB : WINED3D_LOCATION_TEXTURE_SRGB;
2591 wined3d_texture_get_level_box(&texture_gl->t, level, &src_box);
2592 wined3d_texture_get_pitch(&texture_gl->t, level, &row_pitch, &slice_pitch);
2593 wined3d_texture_gl_download_data(&context_gl->c, &texture_gl->t, sub_resource_idx, src_location,
2594 &src_box, &data, texture_gl->t.resource.format, 0, 0, 0, row_pitch, slice_pitch);
2596 ++texture_gl->t.download_count;
2597 return TRUE;
2600 if (!(texture_gl->t.resource.bind_flags & WINED3D_BIND_DEPTH_STENCIL)
2601 && (sub_resource->locations & WINED3D_LOCATION_DRAWABLE))
2603 texture2d_read_from_framebuffer(&texture_gl->t, sub_resource_idx, &context_gl->c,
2604 texture_gl->t.resource.draw_binding, dst_location);
2605 return TRUE;
2608 FIXME("Can't load texture %p, %u with location flags %s into sysmem.\n",
2609 texture_gl, sub_resource_idx, wined3d_debug_location(sub_resource->locations));
2611 return FALSE;
2614 static BOOL wined3d_texture_load_drawable(struct wined3d_texture *texture,
2615 unsigned int sub_resource_idx, struct wined3d_context *context)
2617 struct wined3d_device *device;
2618 unsigned int level;
2619 RECT r;
2621 if (texture->resource.bind_flags & WINED3D_BIND_DEPTH_STENCIL)
2623 DWORD current = texture->sub_resources[sub_resource_idx].locations;
2624 FIXME("Unimplemented copy from %s for depth/stencil buffers.\n",
2625 wined3d_debug_location(current));
2626 return FALSE;
2629 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO
2630 && wined3d_resource_is_offscreen(&texture->resource))
2632 ERR("Trying to load offscreen texture into WINED3D_LOCATION_DRAWABLE.\n");
2633 return FALSE;
2636 device = texture->resource.device;
2637 level = sub_resource_idx % texture->level_count;
2638 SetRect(&r, 0, 0, wined3d_texture_get_level_width(texture, level),
2639 wined3d_texture_get_level_height(texture, level));
2640 wined3d_texture_load_location(texture, sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB);
2641 device->blitter->ops->blitter_blit(device->blitter, WINED3D_BLIT_OP_COLOR_BLIT, context,
2642 texture, sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB, &r,
2643 texture, sub_resource_idx, WINED3D_LOCATION_DRAWABLE, &r,
2644 NULL, WINED3D_TEXF_POINT);
2646 return TRUE;
2649 static BOOL wined3d_texture_load_renderbuffer(struct wined3d_texture *texture,
2650 unsigned int sub_resource_idx, struct wined3d_context *context, DWORD dst_location)
2652 unsigned int level = sub_resource_idx % texture->level_count;
2653 const RECT rect = {0, 0,
2654 wined3d_texture_get_level_width(texture, level),
2655 wined3d_texture_get_level_height(texture, level)};
2656 struct wined3d_texture_sub_resource *sub_resource;
2657 DWORD src_location, locations;
2659 sub_resource = &texture->sub_resources[sub_resource_idx];
2660 locations = sub_resource->locations;
2661 if (texture->resource.bind_flags & WINED3D_BIND_DEPTH_STENCIL)
2663 FIXME("Unimplemented copy from %s for depth/stencil buffers.\n",
2664 wined3d_debug_location(locations));
2665 return FALSE;
2668 if (locations & WINED3D_LOCATION_RB_MULTISAMPLE)
2669 src_location = WINED3D_LOCATION_RB_MULTISAMPLE;
2670 else if (locations & WINED3D_LOCATION_RB_RESOLVED)
2671 src_location = WINED3D_LOCATION_RB_RESOLVED;
2672 else if (locations & WINED3D_LOCATION_TEXTURE_SRGB)
2673 src_location = WINED3D_LOCATION_TEXTURE_SRGB;
2674 else if (locations & WINED3D_LOCATION_TEXTURE_RGB)
2675 src_location = WINED3D_LOCATION_TEXTURE_RGB;
2676 else if (locations & WINED3D_LOCATION_DRAWABLE)
2677 src_location = WINED3D_LOCATION_DRAWABLE;
2678 else /* texture2d_blt_fbo() will load the source location if necessary. */
2679 src_location = WINED3D_LOCATION_TEXTURE_RGB;
2681 texture2d_blt_fbo(texture->resource.device, context, WINED3D_TEXF_POINT, texture,
2682 sub_resource_idx, src_location, &rect, texture, sub_resource_idx, dst_location, &rect);
2684 return TRUE;
2687 static BOOL wined3d_texture_gl_load_texture(struct wined3d_texture_gl *texture_gl,
2688 unsigned int sub_resource_idx, struct wined3d_context_gl *context_gl, BOOL srgb)
2690 unsigned int width, height, level, src_row_pitch, src_slice_pitch, dst_row_pitch, dst_slice_pitch;
2691 struct wined3d_device *device = texture_gl->t.resource.device;
2692 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
2693 const struct wined3d_color_key_conversion *conversion;
2694 struct wined3d_texture_sub_resource *sub_resource;
2695 const struct wined3d_format *format;
2696 struct wined3d_bo_address data;
2697 BYTE *src_mem, *dst_mem = NULL;
2698 struct wined3d_box src_box;
2699 DWORD dst_location;
2700 BOOL depth;
2702 depth = texture_gl->t.resource.bind_flags & WINED3D_BIND_DEPTH_STENCIL;
2703 sub_resource = &texture_gl->t.sub_resources[sub_resource_idx];
2705 if (!depth && wined3d_settings.offscreen_rendering_mode != ORM_FBO
2706 && wined3d_resource_is_offscreen(&texture_gl->t.resource)
2707 && (sub_resource->locations & WINED3D_LOCATION_DRAWABLE))
2709 texture2d_load_fb_texture(texture_gl, sub_resource_idx, srgb, &context_gl->c);
2711 return TRUE;
2714 level = sub_resource_idx % texture_gl->t.level_count;
2715 wined3d_texture_get_level_box(&texture_gl->t, level, &src_box);
2717 if (!depth && sub_resource->locations & (WINED3D_LOCATION_TEXTURE_SRGB | WINED3D_LOCATION_TEXTURE_RGB)
2718 && (texture_gl->t.resource.format_flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB)
2719 && fbo_blitter_supported(WINED3D_BLIT_OP_COLOR_BLIT, gl_info,
2720 &texture_gl->t.resource, WINED3D_LOCATION_TEXTURE_RGB,
2721 &texture_gl->t.resource, WINED3D_LOCATION_TEXTURE_SRGB))
2723 RECT src_rect;
2725 SetRect(&src_rect, src_box.left, src_box.top, src_box.right, src_box.bottom);
2726 if (srgb)
2727 texture2d_blt_fbo(device, &context_gl->c, WINED3D_TEXF_POINT,
2728 &texture_gl->t, sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB, &src_rect,
2729 &texture_gl->t, sub_resource_idx, WINED3D_LOCATION_TEXTURE_SRGB, &src_rect);
2730 else
2731 texture2d_blt_fbo(device, &context_gl->c, WINED3D_TEXF_POINT,
2732 &texture_gl->t, sub_resource_idx, WINED3D_LOCATION_TEXTURE_SRGB, &src_rect,
2733 &texture_gl->t, sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB, &src_rect);
2735 return TRUE;
2738 if (!depth && sub_resource->locations & (WINED3D_LOCATION_RB_MULTISAMPLE | WINED3D_LOCATION_RB_RESOLVED)
2739 && (!srgb || (texture_gl->t.resource.format_flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB)))
2741 DWORD src_location = sub_resource->locations & WINED3D_LOCATION_RB_RESOLVED ?
2742 WINED3D_LOCATION_RB_RESOLVED : WINED3D_LOCATION_RB_MULTISAMPLE;
2743 RECT src_rect;
2745 SetRect(&src_rect, src_box.left, src_box.top, src_box.right, src_box.bottom);
2746 dst_location = srgb ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB;
2747 if (fbo_blitter_supported(WINED3D_BLIT_OP_COLOR_BLIT, gl_info,
2748 &texture_gl->t.resource, src_location, &texture_gl->t.resource, dst_location))
2749 texture2d_blt_fbo(device, &context_gl->c, WINED3D_TEXF_POINT, &texture_gl->t, sub_resource_idx,
2750 src_location, &src_rect, &texture_gl->t, sub_resource_idx, dst_location, &src_rect);
2752 return TRUE;
2755 /* Upload from system memory */
2757 if (srgb)
2759 dst_location = WINED3D_LOCATION_TEXTURE_SRGB;
2760 if ((sub_resource->locations & (WINED3D_LOCATION_TEXTURE_RGB | texture_gl->t.resource.map_binding))
2761 == WINED3D_LOCATION_TEXTURE_RGB)
2763 FIXME_(d3d_perf)("Downloading RGB texture %p, %u to reload it as sRGB.\n", texture_gl, sub_resource_idx);
2764 wined3d_texture_load_location(&texture_gl->t, sub_resource_idx,
2765 &context_gl->c, texture_gl->t.resource.map_binding);
2768 else
2770 dst_location = WINED3D_LOCATION_TEXTURE_RGB;
2771 if ((sub_resource->locations & (WINED3D_LOCATION_TEXTURE_SRGB | texture_gl->t.resource.map_binding))
2772 == WINED3D_LOCATION_TEXTURE_SRGB)
2774 FIXME_(d3d_perf)("Downloading sRGB texture %p, %u to reload it as RGB.\n", texture_gl, sub_resource_idx);
2775 wined3d_texture_load_location(&texture_gl->t, sub_resource_idx,
2776 &context_gl->c, texture_gl->t.resource.map_binding);
2780 if (!(sub_resource->locations & wined3d_texture_sysmem_locations))
2782 WARN("Trying to load a texture from sysmem, but no simple location is valid.\n");
2783 /* Lets hope we get it from somewhere... */
2784 wined3d_texture_load_location(&texture_gl->t, sub_resource_idx, &context_gl->c, WINED3D_LOCATION_SYSMEM);
2787 wined3d_texture_get_pitch(&texture_gl->t, level, &src_row_pitch, &src_slice_pitch);
2789 format = texture_gl->t.resource.format;
2790 if ((conversion = wined3d_format_get_color_key_conversion(&texture_gl->t, TRUE)))
2791 format = wined3d_get_format(device->adapter, conversion->dst_format, texture_gl->t.resource.bind_flags);
2793 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
2794 * WINED3D_TEXTURE_CONVERTED but it isn't set (yet) in all cases it is
2795 * getting called. */
2796 if (conversion && sub_resource->buffer_object)
2798 TRACE("Removing the pbo attached to texture %p, %u.\n", texture_gl, sub_resource_idx);
2800 wined3d_texture_load_location(&texture_gl->t, sub_resource_idx, &context_gl->c, WINED3D_LOCATION_SYSMEM);
2801 wined3d_texture_set_map_binding(&texture_gl->t, WINED3D_LOCATION_SYSMEM);
2804 wined3d_texture_get_memory(&texture_gl->t, sub_resource_idx, &data, sub_resource->locations);
2805 if (conversion)
2807 width = src_box.right - src_box.left;
2808 height = src_box.bottom - src_box.top;
2809 wined3d_format_calculate_pitch(format, device->surface_alignment,
2810 width, height, &dst_row_pitch, &dst_slice_pitch);
2812 src_mem = wined3d_context_gl_map_bo_address(context_gl, &data,
2813 src_slice_pitch, GL_PIXEL_UNPACK_BUFFER, WINED3D_MAP_READ);
2814 if (!(dst_mem = heap_alloc(dst_slice_pitch)))
2816 ERR("Out of memory (%u).\n", dst_slice_pitch);
2817 return FALSE;
2819 conversion->convert(src_mem, src_row_pitch, dst_mem, dst_row_pitch,
2820 width, height, &texture_gl->t.async.gl_color_key);
2821 src_row_pitch = dst_row_pitch;
2822 src_slice_pitch = dst_slice_pitch;
2823 wined3d_context_gl_unmap_bo_address(context_gl, &data, GL_PIXEL_UNPACK_BUFFER, 0, NULL);
2825 data.buffer_object = 0;
2826 data.addr = dst_mem;
2829 wined3d_texture_gl_upload_data(&context_gl->c, wined3d_const_bo_address(&data), format, &src_box,
2830 src_row_pitch, src_slice_pitch, &texture_gl->t, sub_resource_idx, dst_location, 0, 0, 0);
2832 heap_free(dst_mem);
2834 return TRUE;
2837 static BOOL wined3d_texture_gl_prepare_location(struct wined3d_texture *texture,
2838 unsigned int sub_resource_idx, struct wined3d_context *context, unsigned int location)
2840 struct wined3d_texture_gl *texture_gl = wined3d_texture_gl(texture);
2841 struct wined3d_context_gl *context_gl = wined3d_context_gl(context);
2843 switch (location)
2845 case WINED3D_LOCATION_SYSMEM:
2846 return wined3d_resource_prepare_sysmem(&texture->resource);
2848 case WINED3D_LOCATION_USER_MEMORY:
2849 if (!texture->user_memory)
2850 ERR("Preparing WINED3D_LOCATION_USER_MEMORY, but texture->user_memory is NULL.\n");
2851 return TRUE;
2853 case WINED3D_LOCATION_BUFFER:
2854 wined3d_texture_prepare_buffer_object(texture, sub_resource_idx, context_gl->gl_info);
2855 return TRUE;
2857 case WINED3D_LOCATION_TEXTURE_RGB:
2858 wined3d_texture_gl_prepare_texture(texture_gl, context_gl, FALSE);
2859 return TRUE;
2861 case WINED3D_LOCATION_TEXTURE_SRGB:
2862 wined3d_texture_gl_prepare_texture(texture_gl, context_gl, TRUE);
2863 return TRUE;
2865 case WINED3D_LOCATION_DRAWABLE:
2866 if (!texture->swapchain && wined3d_settings.offscreen_rendering_mode != ORM_BACKBUFFER)
2867 ERR("Texture %p does not have a drawable.\n", texture);
2868 return TRUE;
2870 case WINED3D_LOCATION_RB_MULTISAMPLE:
2871 wined3d_texture_gl_prepare_rb(texture_gl, context_gl->gl_info, TRUE);
2872 return TRUE;
2874 case WINED3D_LOCATION_RB_RESOLVED:
2875 wined3d_texture_gl_prepare_rb(texture_gl, context_gl->gl_info, FALSE);
2876 return TRUE;
2878 default:
2879 ERR("Invalid location %s.\n", wined3d_debug_location(location));
2880 return FALSE;
2884 /* Context activation is done by the caller. */
2885 static BOOL wined3d_texture_gl_load_location(struct wined3d_texture *texture,
2886 unsigned int sub_resource_idx, struct wined3d_context *context, DWORD location)
2888 struct wined3d_texture_gl *texture_gl = wined3d_texture_gl(texture);
2889 struct wined3d_context_gl *context_gl = wined3d_context_gl(context);
2891 TRACE("texture %p, sub_resource_idx %u, context %p, location %s.\n",
2892 texture, sub_resource_idx, context, wined3d_debug_location(location));
2894 if (!wined3d_texture_gl_prepare_location(texture, sub_resource_idx, context, location))
2895 return FALSE;
2897 switch (location)
2899 case WINED3D_LOCATION_USER_MEMORY:
2900 case WINED3D_LOCATION_SYSMEM:
2901 case WINED3D_LOCATION_BUFFER:
2902 return wined3d_texture_gl_load_sysmem(texture_gl, sub_resource_idx, context_gl, location);
2904 case WINED3D_LOCATION_DRAWABLE:
2905 return wined3d_texture_load_drawable(texture, sub_resource_idx, context);
2907 case WINED3D_LOCATION_RB_RESOLVED:
2908 case WINED3D_LOCATION_RB_MULTISAMPLE:
2909 return wined3d_texture_load_renderbuffer(texture, sub_resource_idx, context, location);
2911 case WINED3D_LOCATION_TEXTURE_RGB:
2912 case WINED3D_LOCATION_TEXTURE_SRGB:
2913 return wined3d_texture_gl_load_texture(texture_gl, sub_resource_idx,
2914 context_gl, location == WINED3D_LOCATION_TEXTURE_SRGB);
2916 default:
2917 FIXME("Unhandled %s load from %s.\n", wined3d_debug_location(location),
2918 wined3d_debug_location(texture->sub_resources[sub_resource_idx].locations));
2919 return FALSE;
2923 static void wined3d_texture_gl_unload_location(struct wined3d_texture *texture,
2924 struct wined3d_context *context, unsigned int location)
2926 struct wined3d_texture_gl *texture_gl = wined3d_texture_gl(texture);
2927 struct wined3d_context_gl *context_gl = wined3d_context_gl(context);
2928 struct wined3d_renderbuffer_entry *entry, *entry2;
2929 unsigned int i, sub_count;
2931 TRACE("texture %p, context %p, location %s.\n", texture, context, wined3d_debug_location(location));
2933 switch (location)
2935 case WINED3D_LOCATION_BUFFER:
2936 sub_count = texture->level_count * texture->layer_count;
2937 for (i = 0; i < sub_count; ++i)
2939 if (texture_gl->t.sub_resources[i].buffer_object)
2940 wined3d_texture_remove_buffer_object(&texture_gl->t, i, context_gl->gl_info);
2942 break;
2944 case WINED3D_LOCATION_TEXTURE_RGB:
2945 if (texture_gl->texture_rgb.name)
2946 gltexture_delete(texture_gl->t.resource.device, context_gl->gl_info, &texture_gl->texture_rgb);
2947 break;
2949 case WINED3D_LOCATION_TEXTURE_SRGB:
2950 if (texture_gl->texture_srgb.name)
2951 gltexture_delete(texture_gl->t.resource.device, context_gl->gl_info, &texture_gl->texture_srgb);
2952 break;
2954 case WINED3D_LOCATION_RB_MULTISAMPLE:
2955 if (texture_gl->rb_multisample)
2957 TRACE("Deleting multisample renderbuffer %u.\n", texture_gl->rb_multisample);
2958 context_gl_resource_released(texture_gl->t.resource.device, texture_gl->rb_multisample, TRUE);
2959 context_gl->gl_info->fbo_ops.glDeleteRenderbuffers(1, &texture_gl->rb_multisample);
2960 texture_gl->rb_multisample = 0;
2962 break;
2964 case WINED3D_LOCATION_RB_RESOLVED:
2965 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &texture_gl->renderbuffers,
2966 struct wined3d_renderbuffer_entry, entry)
2968 context_gl_resource_released(texture_gl->t.resource.device, entry->id, TRUE);
2969 context_gl->gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id);
2970 list_remove(&entry->entry);
2971 heap_free(entry);
2973 list_init(&texture_gl->renderbuffers);
2974 texture_gl->current_renderbuffer = NULL;
2976 if (texture_gl->rb_resolved)
2978 TRACE("Deleting resolved renderbuffer %u.\n", texture_gl->rb_resolved);
2979 context_gl_resource_released(texture_gl->t.resource.device, texture_gl->rb_resolved, TRUE);
2980 context_gl->gl_info->fbo_ops.glDeleteRenderbuffers(1, &texture_gl->rb_resolved);
2981 texture_gl->rb_resolved = 0;
2983 break;
2985 default:
2986 ERR("Unhandled location %s.\n", wined3d_debug_location(location));
2987 break;
2991 static const struct wined3d_texture_ops texture_gl_ops =
2993 wined3d_texture_gl_prepare_location,
2994 wined3d_texture_gl_load_location,
2995 wined3d_texture_gl_unload_location,
2996 wined3d_texture_gl_upload_data,
2997 wined3d_texture_gl_download_data,
3000 struct wined3d_texture * __cdecl wined3d_texture_from_resource(struct wined3d_resource *resource)
3002 return texture_from_resource(resource);
3005 static ULONG texture_resource_incref(struct wined3d_resource *resource)
3007 return wined3d_texture_incref(texture_from_resource(resource));
3010 static ULONG texture_resource_decref(struct wined3d_resource *resource)
3012 return wined3d_texture_decref(texture_from_resource(resource));
3015 static void texture_resource_preload(struct wined3d_resource *resource)
3017 struct wined3d_texture *texture = texture_from_resource(resource);
3018 struct wined3d_context *context;
3020 context = context_acquire(resource->device, NULL, 0);
3021 wined3d_texture_load(texture, context, texture->flags & WINED3D_TEXTURE_IS_SRGB);
3022 context_release(context);
3025 static void texture_resource_unload(struct wined3d_resource *resource)
3027 struct wined3d_texture *texture = texture_from_resource(resource);
3028 struct wined3d_device *device = resource->device;
3029 unsigned int location = resource->map_binding;
3030 struct wined3d_context *context;
3031 unsigned int sub_count, i;
3033 TRACE("resource %p.\n", resource);
3035 /* D3D is not initialised, so no GPU locations should currently exist.
3036 * Moreover, we may not be able to acquire a valid context. */
3037 if (!device->d3d_initialized)
3038 return;
3040 context = context_acquire(device, NULL, 0);
3042 if (location == WINED3D_LOCATION_BUFFER)
3043 location = WINED3D_LOCATION_SYSMEM;
3045 sub_count = texture->level_count * texture->layer_count;
3046 for (i = 0; i < sub_count; ++i)
3048 if (resource->access & WINED3D_RESOURCE_ACCESS_CPU
3049 && wined3d_texture_load_location(texture, i, context, location))
3051 wined3d_texture_invalidate_location(texture, i, ~location);
3053 else
3055 if (resource->access & WINED3D_RESOURCE_ACCESS_CPU)
3056 ERR("Discarding %s %p sub-resource %u with resource access %s.\n",
3057 debug_d3dresourcetype(resource->type), resource, i,
3058 wined3d_debug_resource_access(resource->access));
3059 wined3d_texture_validate_location(texture, i, WINED3D_LOCATION_DISCARDED);
3060 wined3d_texture_invalidate_location(texture, i, ~WINED3D_LOCATION_DISCARDED);
3064 wined3d_texture_unload_location(texture, context, WINED3D_LOCATION_BUFFER);
3065 wined3d_texture_unload_location(texture, context, WINED3D_LOCATION_TEXTURE_RGB);
3066 wined3d_texture_unload_location(texture, context, WINED3D_LOCATION_TEXTURE_SRGB);
3067 wined3d_texture_unload_location(texture, context, WINED3D_LOCATION_RB_MULTISAMPLE);
3068 wined3d_texture_unload_location(texture, context, WINED3D_LOCATION_RB_RESOLVED);
3070 context_release(context);
3072 wined3d_texture_force_reload(texture);
3073 if (texture->resource.bind_count)
3074 device_invalidate_state(device, STATE_SAMPLER(texture->sampler));
3075 wined3d_texture_set_dirty(texture);
3077 resource_unload(&texture->resource);
3080 static HRESULT texture_resource_sub_resource_map(struct wined3d_resource *resource, unsigned int sub_resource_idx,
3081 struct wined3d_map_desc *map_desc, const struct wined3d_box *box, DWORD flags)
3083 const struct wined3d_format *format = resource->format;
3084 struct wined3d_texture_sub_resource *sub_resource;
3085 struct wined3d_device *device = resource->device;
3086 unsigned int fmt_flags = resource->format_flags;
3087 struct wined3d_context *context;
3088 struct wined3d_texture *texture;
3089 struct wined3d_bo_address data;
3090 unsigned int texture_level;
3091 BYTE *base_memory;
3092 BOOL ret;
3094 TRACE("resource %p, sub_resource_idx %u, map_desc %p, box %s, flags %#x.\n",
3095 resource, sub_resource_idx, map_desc, debug_box(box), flags);
3097 texture = texture_from_resource(resource);
3098 if (!(sub_resource = wined3d_texture_get_sub_resource(texture, sub_resource_idx)))
3099 return E_INVALIDARG;
3101 texture_level = sub_resource_idx % texture->level_count;
3102 if (box && FAILED(wined3d_texture_check_box_dimensions(texture, texture_level, box)))
3104 WARN("Map box is invalid.\n");
3105 if (((fmt_flags & WINED3DFMT_FLAG_BLOCKS) && !(resource->access & WINED3D_RESOURCE_ACCESS_CPU))
3106 || resource->type != WINED3D_RTYPE_TEXTURE_2D)
3107 return WINED3DERR_INVALIDCALL;
3110 if (texture->flags & WINED3D_TEXTURE_DC_IN_USE)
3112 WARN("DC is in use.\n");
3113 return WINED3DERR_INVALIDCALL;
3116 if (sub_resource->map_count)
3118 WARN("Sub-resource is already mapped.\n");
3119 return WINED3DERR_INVALIDCALL;
3122 context = context_acquire(device, NULL, 0);
3124 if (flags & WINED3D_MAP_DISCARD)
3126 TRACE("WINED3D_MAP_DISCARD flag passed, marking %s as up to date.\n",
3127 wined3d_debug_location(resource->map_binding));
3128 if ((ret = wined3d_texture_prepare_location(texture, sub_resource_idx, context, resource->map_binding)))
3129 wined3d_texture_validate_location(texture, sub_resource_idx, resource->map_binding);
3131 else
3133 if (resource->usage & WINED3DUSAGE_DYNAMIC)
3134 WARN_(d3d_perf)("Mapping a dynamic texture without WINED3D_MAP_DISCARD.\n");
3135 ret = wined3d_texture_load_location(texture, sub_resource_idx, context, resource->map_binding);
3138 if (!ret)
3140 ERR("Failed to prepare location.\n");
3141 context_release(context);
3142 return E_OUTOFMEMORY;
3145 /* We only record dirty regions for the top-most level. */
3146 if (texture->dirty_regions && flags & WINED3D_MAP_WRITE
3147 && !(flags & WINED3D_MAP_NO_DIRTY_UPDATE) && !texture_level)
3148 wined3d_texture_dirty_region_add(texture, sub_resource_idx / texture->level_count, box);
3150 if (flags & WINED3D_MAP_WRITE
3151 && (!(flags & WINED3D_MAP_NO_DIRTY_UPDATE) || (resource->usage & WINED3DUSAGE_DYNAMIC)))
3152 wined3d_texture_invalidate_location(texture, sub_resource_idx, ~resource->map_binding);
3154 wined3d_texture_get_memory(texture, sub_resource_idx, &data, resource->map_binding);
3155 base_memory = wined3d_context_map_bo_address(context, &data, sub_resource->size, 0, flags);
3156 sub_resource->map_flags = flags;
3157 TRACE("Base memory pointer %p.\n", base_memory);
3159 context_release(context);
3161 if (fmt_flags & WINED3DFMT_FLAG_BROKEN_PITCH)
3163 map_desc->row_pitch = wined3d_texture_get_level_width(texture, texture_level) * format->byte_count;
3164 map_desc->slice_pitch = wined3d_texture_get_level_height(texture, texture_level) * map_desc->row_pitch;
3166 else
3168 wined3d_texture_get_pitch(texture, texture_level, &map_desc->row_pitch, &map_desc->slice_pitch);
3171 if (!box)
3173 map_desc->data = base_memory;
3175 else
3177 if ((fmt_flags & (WINED3DFMT_FLAG_BLOCKS | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_BLOCKS)
3179 /* Compressed textures are block based, so calculate the offset of
3180 * the block that contains the top-left pixel of the mapped box. */
3181 map_desc->data = base_memory
3182 + (box->front * map_desc->slice_pitch)
3183 + ((box->top / format->block_height) * map_desc->row_pitch)
3184 + ((box->left / format->block_width) * format->block_byte_count);
3186 else
3188 map_desc->data = base_memory
3189 + (box->front * map_desc->slice_pitch)
3190 + (box->top * map_desc->row_pitch)
3191 + (box->left * format->byte_count);
3195 if (texture->swapchain && texture->swapchain->front_buffer == texture)
3197 RECT *r = &texture->swapchain->front_buffer_update;
3199 if (!box)
3200 SetRect(r, 0, 0, resource->width, resource->height);
3201 else
3202 SetRect(r, box->left, box->top, box->right, box->bottom);
3203 TRACE("Mapped front buffer %s.\n", wine_dbgstr_rect(r));
3206 ++resource->map_count;
3207 ++sub_resource->map_count;
3209 TRACE("Returning memory %p, row pitch %u, slice pitch %u.\n",
3210 map_desc->data, map_desc->row_pitch, map_desc->slice_pitch);
3212 return WINED3D_OK;
3215 static HRESULT texture_resource_sub_resource_unmap(struct wined3d_resource *resource, unsigned int sub_resource_idx)
3217 struct wined3d_texture_sub_resource *sub_resource;
3218 struct wined3d_device *device = resource->device;
3219 struct wined3d_context *context;
3220 struct wined3d_texture *texture;
3221 struct wined3d_bo_address data;
3222 struct wined3d_range range;
3224 TRACE("resource %p, sub_resource_idx %u.\n", resource, sub_resource_idx);
3226 texture = texture_from_resource(resource);
3227 if (!(sub_resource = wined3d_texture_get_sub_resource(texture, sub_resource_idx)))
3228 return E_INVALIDARG;
3230 if (!sub_resource->map_count)
3232 WARN("Trying to unmap unmapped sub-resource.\n");
3233 if (texture->flags & WINED3D_TEXTURE_DC_IN_USE)
3234 return WINED3D_OK;
3235 return WINEDDERR_NOTLOCKED;
3238 context = context_acquire(device, NULL, 0);
3240 wined3d_texture_get_memory(texture, sub_resource_idx, &data, texture->resource.map_binding);
3241 range.offset = 0;
3242 range.size = sub_resource->size;
3243 wined3d_context_unmap_bo_address(context, &data, 0, !!(sub_resource->map_flags & WINED3D_MAP_WRITE), &range);
3245 context_release(context);
3247 if (texture->swapchain && texture->swapchain->front_buffer == texture)
3249 if (!(sub_resource->locations & (WINED3D_LOCATION_DRAWABLE | WINED3D_LOCATION_TEXTURE_RGB)))
3250 texture->swapchain->swapchain_ops->swapchain_frontbuffer_updated(texture->swapchain);
3253 --sub_resource->map_count;
3254 if (!--resource->map_count && texture->update_map_binding)
3255 wined3d_texture_update_map_binding(texture);
3257 return WINED3D_OK;
3260 static const struct wined3d_resource_ops texture_resource_ops =
3262 texture_resource_incref,
3263 texture_resource_decref,
3264 texture_resource_preload,
3265 texture_resource_unload,
3266 texture_resource_sub_resource_map,
3267 texture_resource_sub_resource_unmap,
3270 static HRESULT wined3d_texture_init(struct wined3d_texture *texture, const struct wined3d_resource_desc *desc,
3271 unsigned int layer_count, unsigned int level_count, DWORD flags, struct wined3d_device *device,
3272 void *parent, const struct wined3d_parent_ops *parent_ops, void *sub_resources,
3273 const struct wined3d_texture_ops *texture_ops)
3275 const struct wined3d_d3d_info *d3d_info = &device->adapter->d3d_info;
3276 struct wined3d_device_parent *device_parent = device->device_parent;
3277 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
3278 unsigned int sub_count, i, j, size, offset = 0;
3279 unsigned int pow2_width, pow2_height;
3280 const struct wined3d_format *format;
3281 HRESULT hr;
3283 TRACE("texture %p, resource_type %s, format %s, multisample_type %#x, multisample_quality %#x, "
3284 "usage %s, access %s, width %u, height %u, depth %u, layer_count %u, level_count %u, "
3285 "flags %#x, device %p, parent %p, parent_ops %p, sub_resources %p, texture_ops %p.\n",
3286 texture, debug_d3dresourcetype(desc->resource_type), debug_d3dformat(desc->format),
3287 desc->multisample_type, desc->multisample_quality, debug_d3dusage(desc->usage),
3288 wined3d_debug_resource_access(desc->access), desc->width, desc->height, desc->depth,
3289 layer_count, level_count, flags, device, parent, parent_ops, sub_resources, texture_ops);
3291 if (!desc->width || !desc->height || !desc->depth)
3292 return WINED3DERR_INVALIDCALL;
3294 if (desc->resource_type == WINED3D_RTYPE_TEXTURE_3D && layer_count != 1)
3296 ERR("Invalid layer count for volume texture.\n");
3297 return E_INVALIDARG;
3300 texture->sub_resources = sub_resources;
3302 /* TODO: It should only be possible to create textures for formats
3303 * that are reported as supported. */
3304 if (WINED3DFMT_UNKNOWN >= desc->format)
3306 WARN("Texture cannot be created with a format of WINED3DFMT_UNKNOWN.\n");
3307 return WINED3DERR_INVALIDCALL;
3309 format = wined3d_get_format(device->adapter, desc->format, desc->bind_flags);
3311 if (desc->usage & WINED3DUSAGE_DYNAMIC && (wined3d_resource_access_is_managed(desc->access)
3312 || desc->usage & WINED3DUSAGE_SCRATCH))
3314 WARN("Attempted to create a dynamic texture with access %s and usage %s.\n",
3315 wined3d_debug_resource_access(desc->access), debug_d3dusage(desc->usage));
3316 return WINED3DERR_INVALIDCALL;
3319 pow2_width = desc->width;
3320 pow2_height = desc->height;
3321 if (((desc->width & (desc->width - 1)) || (desc->height & (desc->height - 1)) || (desc->depth & (desc->depth - 1)))
3322 && !d3d_info->texture_npot)
3324 /* level_count == 0 returns an error as well. */
3325 if (level_count != 1 || layer_count != 1 || desc->resource_type == WINED3D_RTYPE_TEXTURE_3D)
3327 if (!(desc->usage & WINED3DUSAGE_SCRATCH))
3329 WARN("Attempted to create a mipmapped/cube/array/volume NPOT "
3330 "texture without unconditional NPOT support.\n");
3331 return WINED3DERR_INVALIDCALL;
3334 WARN("Creating a scratch mipmapped/cube/array NPOT texture despite lack of HW support.\n");
3336 texture->flags |= WINED3D_TEXTURE_COND_NP2;
3338 if (desc->resource_type != WINED3D_RTYPE_TEXTURE_3D && !d3d_info->texture_npot_conditional)
3340 /* TODO: Add support for non-power-of-two compressed textures. */
3341 if (format->flags[WINED3D_GL_RES_TYPE_TEX_2D]
3342 & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_HEIGHT_SCALE))
3344 FIXME("Compressed or height scaled non-power-of-two (%ux%u) textures are not supported.\n",
3345 desc->width, desc->height);
3346 return WINED3DERR_NOTAVAILABLE;
3349 /* Find the nearest pow2 match. */
3350 pow2_width = pow2_height = 1;
3351 while (pow2_width < desc->width)
3352 pow2_width <<= 1;
3353 while (pow2_height < desc->height)
3354 pow2_height <<= 1;
3355 texture->flags |= WINED3D_TEXTURE_COND_NP2_EMULATED;
3358 texture->pow2_width = pow2_width;
3359 texture->pow2_height = pow2_height;
3361 if ((pow2_width > d3d_info->limits.texture_size || pow2_height > d3d_info->limits.texture_size)
3362 && (desc->bind_flags & WINED3D_BIND_SHADER_RESOURCE))
3364 /* One of four options:
3365 * 1: Do the same as we do with NPOT and scale the texture. (Any
3366 * texture ops would require the texture to be scaled which is
3367 * potentially slow.)
3368 * 2: Set the texture to the maximum size (bad idea).
3369 * 3: WARN and return WINED3DERR_NOTAVAILABLE.
3370 * 4: Create the surface, but allow it to be used only for DirectDraw
3371 * Blts. Some apps (e.g. Swat 3) create textures with a height of
3372 * 16 and a width > 3000 and blt 16x16 letter areas from them to
3373 * the render target. */
3374 if (desc->access & WINED3D_RESOURCE_ACCESS_GPU)
3376 WARN("Dimensions (%ux%u) exceed the maximum texture size.\n", pow2_width, pow2_height);
3377 return WINED3DERR_NOTAVAILABLE;
3380 /* We should never use this surface in combination with OpenGL. */
3381 TRACE("Creating an oversized (%ux%u) surface.\n", pow2_width, pow2_height);
3384 for (i = 0; i < layer_count; ++i)
3386 for (j = 0; j < level_count; ++j)
3388 unsigned int idx = i * level_count + j;
3390 size = wined3d_format_calculate_size(format, device->surface_alignment,
3391 max(1, desc->width >> j), max(1, desc->height >> j), max(1, desc->depth >> j));
3392 texture->sub_resources[idx].offset = offset;
3393 texture->sub_resources[idx].size = size;
3394 offset += size;
3396 offset = (offset + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1);
3399 if (!offset)
3400 return WINED3DERR_INVALIDCALL;
3402 if (FAILED(hr = resource_init(&texture->resource, device, desc->resource_type, format,
3403 desc->multisample_type, desc->multisample_quality, desc->usage, desc->bind_flags, desc->access,
3404 desc->width, desc->height, desc->depth, offset, parent, parent_ops, &texture_resource_ops)))
3406 static unsigned int once;
3408 /* DXTn 3D textures are not supported. Do not write the ERR for them. */
3409 if ((desc->format == WINED3DFMT_DXT1 || desc->format == WINED3DFMT_DXT2 || desc->format == WINED3DFMT_DXT3
3410 || desc->format == WINED3DFMT_DXT4 || desc->format == WINED3DFMT_DXT5)
3411 && !(format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_TEXTURE)
3412 && desc->resource_type != WINED3D_RTYPE_TEXTURE_3D && !once++)
3413 ERR_(winediag)("The application tried to create a DXTn texture, but the driver does not support them.\n");
3415 WARN("Failed to initialize resource, returning %#x\n", hr);
3416 return hr;
3418 wined3d_resource_update_draw_binding(&texture->resource);
3420 texture->texture_ops = texture_ops;
3422 texture->layer_count = layer_count;
3423 texture->level_count = level_count;
3424 texture->lod = 0;
3425 texture->flags |= WINED3D_TEXTURE_POW2_MAT_IDENT | WINED3D_TEXTURE_NORMALIZED_COORDS
3426 | WINED3D_TEXTURE_DOWNLOADABLE;
3427 if (flags & WINED3D_TEXTURE_CREATE_GET_DC_LENIENT)
3428 texture->flags |= WINED3D_TEXTURE_PIN_SYSMEM | WINED3D_TEXTURE_GET_DC_LENIENT;
3429 if (flags & (WINED3D_TEXTURE_CREATE_GET_DC | WINED3D_TEXTURE_CREATE_GET_DC_LENIENT))
3430 texture->flags |= WINED3D_TEXTURE_GET_DC;
3431 if (flags & WINED3D_TEXTURE_CREATE_DISCARD)
3432 texture->flags |= WINED3D_TEXTURE_DISCARD;
3433 if (flags & WINED3D_TEXTURE_CREATE_GENERATE_MIPMAPS)
3435 if (!(texture->resource.format_flags & WINED3DFMT_FLAG_GEN_MIPMAP))
3436 WARN("Format doesn't support mipmaps generation, "
3437 "ignoring WINED3D_TEXTURE_CREATE_GENERATE_MIPMAPS flag.\n");
3438 else
3439 texture->flags |= WINED3D_TEXTURE_GENERATE_MIPMAPS;
3442 if (flags & WINED3D_TEXTURE_CREATE_RECORD_DIRTY_REGIONS
3443 && !(texture->dirty_regions = heap_calloc(texture->layer_count, sizeof(*texture->dirty_regions))))
3445 wined3d_texture_cleanup_sync(texture);
3446 return E_OUTOFMEMORY;
3449 /* Precalculated scaling for 'faked' non power of two texture coords. */
3450 if (texture->resource.gl_type == WINED3D_GL_RES_TYPE_TEX_RECT)
3452 texture->pow2_matrix[0] = (float)desc->width;
3453 texture->pow2_matrix[5] = (float)desc->height;
3454 texture->flags &= ~(WINED3D_TEXTURE_POW2_MAT_IDENT | WINED3D_TEXTURE_NORMALIZED_COORDS);
3456 else if (texture->flags & WINED3D_TEXTURE_COND_NP2_EMULATED)
3458 texture->pow2_matrix[0] = (((float)desc->width) / ((float)pow2_width));
3459 texture->pow2_matrix[5] = (((float)desc->height) / ((float)pow2_height));
3460 texture->flags &= ~WINED3D_TEXTURE_POW2_MAT_IDENT;
3462 else
3464 texture->pow2_matrix[0] = 1.0f;
3465 texture->pow2_matrix[5] = 1.0f;
3467 texture->pow2_matrix[10] = 1.0f;
3468 texture->pow2_matrix[15] = 1.0f;
3469 TRACE("x scale %.8e, y scale %.8e.\n", texture->pow2_matrix[0], texture->pow2_matrix[5]);
3471 if (wined3d_texture_use_pbo(texture, gl_info))
3472 texture->resource.map_binding = WINED3D_LOCATION_BUFFER;
3474 if (desc->resource_type != WINED3D_RTYPE_TEXTURE_3D
3475 || !wined3d_texture_use_pbo(texture, gl_info))
3477 if (!wined3d_resource_prepare_sysmem(&texture->resource))
3479 wined3d_texture_cleanup_sync(texture);
3480 return E_OUTOFMEMORY;
3484 sub_count = level_count * layer_count;
3485 if (sub_count / layer_count != level_count)
3487 wined3d_texture_cleanup_sync(texture);
3488 return E_OUTOFMEMORY;
3491 if (desc->usage & WINED3DUSAGE_OVERLAY)
3493 if (!(texture->overlay_info = heap_calloc(sub_count, sizeof(*texture->overlay_info))))
3495 wined3d_texture_cleanup_sync(texture);
3496 return E_OUTOFMEMORY;
3499 for (i = 0; i < sub_count; ++i)
3501 list_init(&texture->overlay_info[i].entry);
3502 list_init(&texture->overlay_info[i].overlays);
3506 /* Generate all sub-resources. */
3507 for (i = 0; i < sub_count; ++i)
3509 struct wined3d_texture_sub_resource *sub_resource;
3511 sub_resource = &texture->sub_resources[i];
3512 sub_resource->locations = WINED3D_LOCATION_DISCARDED;
3513 if (desc->resource_type != WINED3D_RTYPE_TEXTURE_3D)
3515 wined3d_texture_validate_location(texture, i, WINED3D_LOCATION_SYSMEM);
3516 wined3d_texture_invalidate_location(texture, i, ~WINED3D_LOCATION_SYSMEM);
3519 if (FAILED(hr = device_parent->ops->texture_sub_resource_created(device_parent,
3520 desc->resource_type, texture, i, &sub_resource->parent, &sub_resource->parent_ops)))
3522 WARN("Failed to create sub-resource parent, hr %#x.\n", hr);
3523 sub_resource->parent = NULL;
3524 wined3d_texture_cleanup_sync(texture);
3525 return hr;
3528 TRACE("parent %p, parent_ops %p.\n", sub_resource->parent, sub_resource->parent_ops);
3530 TRACE("Created sub-resource %u (level %u, layer %u).\n",
3531 i, i % texture->level_count, i / texture->level_count);
3533 if (desc->usage & WINED3DUSAGE_OWNDC)
3535 struct wined3d_texture_idx texture_idx = {texture, i};
3537 wined3d_cs_init_object(device->cs, wined3d_texture_create_dc, &texture_idx);
3538 wined3d_cs_finish(device->cs, WINED3D_CS_QUEUE_DEFAULT);
3539 if (!texture->dc_info || !texture->dc_info[i].dc)
3541 wined3d_texture_cleanup_sync(texture);
3542 return WINED3DERR_INVALIDCALL;
3547 return WINED3D_OK;
3550 HRESULT CDECL wined3d_texture_blt(struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx,
3551 const RECT *dst_rect, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
3552 const RECT *src_rect, DWORD flags, const struct wined3d_blt_fx *fx, enum wined3d_texture_filter_type filter)
3554 struct wined3d_box src_box = {src_rect->left, src_rect->top, src_rect->right, src_rect->bottom, 0, 1};
3555 struct wined3d_box dst_box = {dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, 0, 1};
3556 unsigned int dst_format_flags, src_format_flags = 0;
3557 HRESULT hr;
3559 TRACE("dst_texture %p, dst_sub_resource_idx %u, dst_rect %s, src_texture %p, "
3560 "src_sub_resource_idx %u, src_rect %s, flags %#x, fx %p, filter %s.\n",
3561 dst_texture, dst_sub_resource_idx, wine_dbgstr_rect(dst_rect), src_texture,
3562 src_sub_resource_idx, wine_dbgstr_rect(src_rect), flags, fx, debug_d3dtexturefiltertype(filter));
3564 if (dst_sub_resource_idx >= dst_texture->level_count * dst_texture->layer_count
3565 || dst_texture->resource.type != WINED3D_RTYPE_TEXTURE_2D)
3566 return WINED3DERR_INVALIDCALL;
3568 if (src_sub_resource_idx >= src_texture->level_count * src_texture->layer_count
3569 || src_texture->resource.type != WINED3D_RTYPE_TEXTURE_2D)
3570 return WINED3DERR_INVALIDCALL;
3572 if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT
3573 && filter != WINED3D_TEXF_LINEAR)
3574 return WINED3DERR_INVALIDCALL;
3576 dst_format_flags = dst_texture->resource.format_flags;
3577 if (FAILED(hr = wined3d_texture_check_box_dimensions(dst_texture,
3578 dst_sub_resource_idx % dst_texture->level_count, &dst_box)))
3579 return hr;
3581 src_format_flags = src_texture->resource.format_flags;
3582 if (FAILED(hr = wined3d_texture_check_box_dimensions(src_texture,
3583 src_sub_resource_idx % src_texture->level_count, &src_box)))
3584 return hr;
3586 if (dst_texture->sub_resources[dst_sub_resource_idx].map_count
3587 || src_texture->sub_resources[src_sub_resource_idx].map_count)
3589 WARN("Sub-resource is busy, returning WINEDDERR_SURFACEBUSY.\n");
3590 return WINEDDERR_SURFACEBUSY;
3593 if ((src_format_flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL))
3594 != (dst_format_flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)))
3596 WARN("Rejecting depth/stencil blit between incompatible formats.\n");
3597 return WINED3DERR_INVALIDCALL;
3600 if (dst_texture->resource.device != src_texture->resource.device)
3602 FIXME("Rejecting cross-device blit.\n");
3603 return E_NOTIMPL;
3606 wined3d_cs_emit_blt_sub_resource(dst_texture->resource.device->cs, &dst_texture->resource, dst_sub_resource_idx,
3607 &dst_box, &src_texture->resource, src_sub_resource_idx, &src_box, flags, fx, filter);
3609 return WINED3D_OK;
3612 HRESULT CDECL wined3d_texture_get_overlay_position(const struct wined3d_texture *texture,
3613 unsigned int sub_resource_idx, LONG *x, LONG *y)
3615 struct wined3d_overlay_info *overlay;
3617 TRACE("texture %p, sub_resource_idx %u, x %p, y %p.\n", texture, sub_resource_idx, x, y);
3619 if (!(texture->resource.usage & WINED3DUSAGE_OVERLAY)
3620 || sub_resource_idx >= texture->level_count * texture->layer_count)
3622 WARN("Invalid sub-resource specified.\n");
3623 return WINEDDERR_NOTAOVERLAYSURFACE;
3626 overlay = &texture->overlay_info[sub_resource_idx];
3627 if (!overlay->dst_texture)
3629 TRACE("Overlay not visible.\n");
3630 *x = 0;
3631 *y = 0;
3632 return WINEDDERR_OVERLAYNOTVISIBLE;
3635 *x = overlay->dst_rect.left;
3636 *y = overlay->dst_rect.top;
3638 TRACE("Returning position %d, %d.\n", *x, *y);
3640 return WINED3D_OK;
3643 HRESULT CDECL wined3d_texture_set_overlay_position(struct wined3d_texture *texture,
3644 unsigned int sub_resource_idx, LONG x, LONG y)
3646 struct wined3d_overlay_info *overlay;
3647 LONG w, h;
3649 TRACE("texture %p, sub_resource_idx %u, x %d, y %d.\n", texture, sub_resource_idx, x, y);
3651 if (!(texture->resource.usage & WINED3DUSAGE_OVERLAY)
3652 || sub_resource_idx >= texture->level_count * texture->layer_count)
3654 WARN("Invalid sub-resource specified.\n");
3655 return WINEDDERR_NOTAOVERLAYSURFACE;
3658 overlay = &texture->overlay_info[sub_resource_idx];
3659 w = overlay->dst_rect.right - overlay->dst_rect.left;
3660 h = overlay->dst_rect.bottom - overlay->dst_rect.top;
3661 SetRect(&overlay->dst_rect, x, y, x + w, y + h);
3663 return WINED3D_OK;
3666 HRESULT CDECL wined3d_texture_update_overlay(struct wined3d_texture *texture, unsigned int sub_resource_idx,
3667 const RECT *src_rect, struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx,
3668 const RECT *dst_rect, DWORD flags)
3670 struct wined3d_overlay_info *overlay;
3671 unsigned int level, dst_level;
3673 TRACE("texture %p, sub_resource_idx %u, src_rect %s, dst_texture %p, "
3674 "dst_sub_resource_idx %u, dst_rect %s, flags %#x.\n",
3675 texture, sub_resource_idx, wine_dbgstr_rect(src_rect), dst_texture,
3676 dst_sub_resource_idx, wine_dbgstr_rect(dst_rect), flags);
3678 if (!(texture->resource.usage & WINED3DUSAGE_OVERLAY) || texture->resource.type != WINED3D_RTYPE_TEXTURE_2D
3679 || sub_resource_idx >= texture->level_count * texture->layer_count)
3681 WARN("Invalid sub-resource specified.\n");
3682 return WINEDDERR_NOTAOVERLAYSURFACE;
3685 if (!dst_texture || dst_texture->resource.type != WINED3D_RTYPE_TEXTURE_2D
3686 || dst_sub_resource_idx >= dst_texture->level_count * dst_texture->layer_count)
3688 WARN("Invalid destination sub-resource specified.\n");
3689 return WINED3DERR_INVALIDCALL;
3692 overlay = &texture->overlay_info[sub_resource_idx];
3694 level = sub_resource_idx % texture->level_count;
3695 if (src_rect)
3696 overlay->src_rect = *src_rect;
3697 else
3698 SetRect(&overlay->src_rect, 0, 0,
3699 wined3d_texture_get_level_width(texture, level),
3700 wined3d_texture_get_level_height(texture, level));
3702 dst_level = dst_sub_resource_idx % dst_texture->level_count;
3703 if (dst_rect)
3704 overlay->dst_rect = *dst_rect;
3705 else
3706 SetRect(&overlay->dst_rect, 0, 0,
3707 wined3d_texture_get_level_width(dst_texture, dst_level),
3708 wined3d_texture_get_level_height(dst_texture, dst_level));
3710 if (overlay->dst_texture && (overlay->dst_texture != dst_texture
3711 || overlay->dst_sub_resource_idx != dst_sub_resource_idx || flags & WINEDDOVER_HIDE))
3713 overlay->dst_texture = NULL;
3714 list_remove(&overlay->entry);
3717 if (flags & WINEDDOVER_SHOW)
3719 if (overlay->dst_texture != dst_texture || overlay->dst_sub_resource_idx != dst_sub_resource_idx)
3721 overlay->dst_texture = dst_texture;
3722 overlay->dst_sub_resource_idx = dst_sub_resource_idx;
3723 list_add_tail(&texture->overlay_info[dst_sub_resource_idx].overlays, &overlay->entry);
3726 else if (flags & WINEDDOVER_HIDE)
3728 /* Tests show that the rectangles are erased on hide. */
3729 SetRectEmpty(&overlay->src_rect);
3730 SetRectEmpty(&overlay->dst_rect);
3731 overlay->dst_texture = NULL;
3734 return WINED3D_OK;
3737 void * CDECL wined3d_texture_get_sub_resource_parent(struct wined3d_texture *texture, unsigned int sub_resource_idx)
3739 unsigned int sub_count = texture->level_count * texture->layer_count;
3741 TRACE("texture %p, sub_resource_idx %u.\n", texture, sub_resource_idx);
3743 if (sub_resource_idx >= sub_count)
3745 WARN("sub_resource_idx %u >= sub_count %u.\n", sub_resource_idx, sub_count);
3746 return NULL;
3749 return texture->sub_resources[sub_resource_idx].parent;
3752 void CDECL wined3d_texture_set_sub_resource_parent(struct wined3d_texture *texture,
3753 unsigned int sub_resource_idx, void *parent)
3755 unsigned int sub_count = texture->level_count * texture->layer_count;
3757 TRACE("texture %p, sub_resource_idx %u, parent %p.\n", texture, sub_resource_idx, parent);
3759 if (sub_resource_idx >= sub_count)
3761 WARN("sub_resource_idx %u >= sub_count %u.\n", sub_resource_idx, sub_count);
3762 return;
3765 texture->sub_resources[sub_resource_idx].parent = parent;
3768 HRESULT CDECL wined3d_texture_get_sub_resource_desc(const struct wined3d_texture *texture,
3769 unsigned int sub_resource_idx, struct wined3d_sub_resource_desc *desc)
3771 unsigned int sub_count = texture->level_count * texture->layer_count;
3772 const struct wined3d_resource *resource;
3773 unsigned int level_idx;
3775 TRACE("texture %p, sub_resource_idx %u, desc %p.\n", texture, sub_resource_idx, desc);
3777 if (sub_resource_idx >= sub_count)
3779 WARN("sub_resource_idx %u >= sub_count %u.\n", sub_resource_idx, sub_count);
3780 return WINED3DERR_INVALIDCALL;
3783 resource = &texture->resource;
3784 desc->format = resource->format->id;
3785 desc->multisample_type = resource->multisample_type;
3786 desc->multisample_quality = resource->multisample_quality;
3787 desc->usage = resource->usage;
3788 desc->bind_flags = resource->bind_flags;
3789 desc->access = resource->access;
3791 level_idx = sub_resource_idx % texture->level_count;
3792 desc->width = wined3d_texture_get_level_width(texture, level_idx);
3793 desc->height = wined3d_texture_get_level_height(texture, level_idx);
3794 desc->depth = wined3d_texture_get_level_depth(texture, level_idx);
3795 desc->size = texture->sub_resources[sub_resource_idx].size;
3797 return WINED3D_OK;
3800 HRESULT wined3d_texture_gl_init(struct wined3d_texture_gl *texture_gl, struct wined3d_device *device,
3801 const struct wined3d_resource_desc *desc, unsigned int layer_count, unsigned int level_count,
3802 uint32_t flags, void *parent, const struct wined3d_parent_ops *parent_ops)
3804 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
3805 HRESULT hr;
3807 TRACE("texture_gl %p, device %p, desc %p, layer_count %u, "
3808 "level_count %u, flags %#x, parent %p, parent_ops %p.\n",
3809 texture_gl, device, desc, layer_count,
3810 level_count, flags, parent, parent_ops);
3812 if (!(desc->usage & WINED3DUSAGE_LEGACY_CUBEMAP) && layer_count > 1
3813 && !gl_info->supported[EXT_TEXTURE_ARRAY])
3815 WARN("OpenGL implementation does not support array textures.\n");
3816 return WINED3DERR_INVALIDCALL;
3819 switch (desc->resource_type)
3821 case WINED3D_RTYPE_TEXTURE_1D:
3822 if (layer_count > 1)
3823 texture_gl->target = GL_TEXTURE_1D_ARRAY;
3824 else
3825 texture_gl->target = GL_TEXTURE_1D;
3826 break;
3828 case WINED3D_RTYPE_TEXTURE_2D:
3829 if (desc->usage & WINED3DUSAGE_LEGACY_CUBEMAP)
3831 texture_gl->target = GL_TEXTURE_CUBE_MAP_ARB;
3833 else if (desc->multisample_type && gl_info->supported[ARB_TEXTURE_MULTISAMPLE])
3835 if (layer_count > 1)
3836 texture_gl->target = GL_TEXTURE_2D_MULTISAMPLE_ARRAY;
3837 else
3838 texture_gl->target = GL_TEXTURE_2D_MULTISAMPLE;
3840 else
3842 if (layer_count > 1)
3843 texture_gl->target = GL_TEXTURE_2D_ARRAY;
3844 else
3845 texture_gl->target = GL_TEXTURE_2D;
3847 break;
3849 case WINED3D_RTYPE_TEXTURE_3D:
3850 if (!gl_info->supported[EXT_TEXTURE3D])
3852 WARN("OpenGL implementation does not support 3D textures.\n");
3853 return WINED3DERR_INVALIDCALL;
3855 texture_gl->target = GL_TEXTURE_3D;
3856 break;
3858 default:
3859 ERR("Invalid resource type %s.\n", debug_d3dresourcetype(desc->resource_type));
3860 return WINED3DERR_INVALIDCALL;
3863 list_init(&texture_gl->renderbuffers);
3865 if (FAILED(hr = wined3d_texture_init(&texture_gl->t, desc, layer_count, level_count,
3866 flags, device, parent, parent_ops, &texture_gl[1], &texture_gl_ops)))
3867 return hr;
3869 if (texture_gl->t.resource.gl_type == WINED3D_GL_RES_TYPE_TEX_RECT)
3870 texture_gl->target = GL_TEXTURE_RECTANGLE_ARB;
3872 if (texture_gl->target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY || texture_gl->target == GL_TEXTURE_2D_MULTISAMPLE)
3873 texture_gl->t.flags &= ~WINED3D_TEXTURE_DOWNLOADABLE;
3875 return WINED3D_OK;
3878 HRESULT CDECL wined3d_texture_create(struct wined3d_device *device, const struct wined3d_resource_desc *desc,
3879 UINT layer_count, UINT level_count, DWORD flags, const struct wined3d_sub_resource_data *data,
3880 void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_texture **texture)
3882 unsigned int sub_count = level_count * layer_count;
3883 unsigned int i;
3884 HRESULT hr;
3886 TRACE("device %p, desc %p, layer_count %u, level_count %u, flags %#x, data %p, "
3887 "parent %p, parent_ops %p, texture %p.\n",
3888 device, desc, layer_count, level_count, flags, data, parent, parent_ops, texture);
3890 if (!layer_count)
3892 WARN("Invalid layer count.\n");
3893 return E_INVALIDARG;
3895 if ((desc->usage & WINED3DUSAGE_LEGACY_CUBEMAP) && layer_count != 6)
3897 ERR("Invalid layer count %u for legacy cubemap.\n", layer_count);
3898 layer_count = 6;
3901 if (!level_count)
3903 WARN("Invalid level count.\n");
3904 return WINED3DERR_INVALIDCALL;
3907 if (desc->multisample_type != WINED3D_MULTISAMPLE_NONE)
3909 const struct wined3d_format *format = wined3d_get_format(device->adapter, desc->format, desc->bind_flags);
3911 if (desc->multisample_type == WINED3D_MULTISAMPLE_NON_MASKABLE
3912 && desc->multisample_quality >= wined3d_popcount(format->multisample_types))
3914 WARN("Unsupported quality level %u requested for WINED3D_MULTISAMPLE_NON_MASKABLE.\n",
3915 desc->multisample_quality);
3916 return WINED3DERR_NOTAVAILABLE;
3918 if (desc->multisample_type != WINED3D_MULTISAMPLE_NON_MASKABLE
3919 && (!(format->multisample_types & 1u << (desc->multisample_type - 1))
3920 || (desc->multisample_quality && desc->multisample_quality != WINED3D_STANDARD_MULTISAMPLE_PATTERN)))
3922 WARN("Unsupported multisample type %u quality %u requested.\n", desc->multisample_type,
3923 desc->multisample_quality);
3924 return WINED3DERR_NOTAVAILABLE;
3928 if (data)
3930 for (i = 0; i < sub_count; ++i)
3932 if (data[i].data)
3933 continue;
3935 WARN("Invalid sub-resource data specified for sub-resource %u.\n", i);
3936 return E_INVALIDARG;
3940 if (FAILED(hr = device->adapter->adapter_ops->adapter_create_texture(device, desc,
3941 layer_count, level_count, flags, parent, parent_ops, texture)))
3942 return hr;
3944 /* FIXME: We'd like to avoid ever allocating system memory for the texture
3945 * in this case. */
3946 if (data)
3948 struct wined3d_box box;
3950 for (i = 0; i < sub_count; ++i)
3952 wined3d_texture_get_level_box(*texture, i % (*texture)->level_count, &box);
3953 wined3d_cs_emit_update_sub_resource(device->cs, &(*texture)->resource,
3954 i, &box, data[i].data, data[i].row_pitch, data[i].slice_pitch);
3958 TRACE("Created texture %p.\n", *texture);
3960 return WINED3D_OK;
3963 HRESULT CDECL wined3d_texture_get_dc(struct wined3d_texture *texture, unsigned int sub_resource_idx, HDC *dc)
3965 struct wined3d_device *device = texture->resource.device;
3966 struct wined3d_texture_sub_resource *sub_resource;
3967 struct wined3d_dc_info *dc_info;
3969 TRACE("texture %p, sub_resource_idx %u, dc %p.\n", texture, sub_resource_idx, dc);
3971 if (!(texture->flags & WINED3D_TEXTURE_GET_DC))
3973 WARN("Texture does not support GetDC\n");
3974 /* Don't touch the DC */
3975 return WINED3DERR_INVALIDCALL;
3978 if (!(sub_resource = wined3d_texture_get_sub_resource(texture, sub_resource_idx)))
3979 return WINED3DERR_INVALIDCALL;
3981 if (texture->resource.type != WINED3D_RTYPE_TEXTURE_2D)
3983 WARN("Not supported on %s resources.\n", debug_d3dresourcetype(texture->resource.type));
3984 return WINED3DERR_INVALIDCALL;
3987 if (texture->resource.map_count && !(texture->flags & WINED3D_TEXTURE_GET_DC_LENIENT))
3988 return WINED3DERR_INVALIDCALL;
3990 if (!(dc_info = texture->dc_info) || !dc_info[sub_resource_idx].dc)
3992 struct wined3d_texture_idx texture_idx = {texture, sub_resource_idx};
3994 wined3d_cs_init_object(device->cs, wined3d_texture_create_dc, &texture_idx);
3995 wined3d_cs_finish(device->cs, WINED3D_CS_QUEUE_DEFAULT);
3996 if (!(dc_info = texture->dc_info) || !dc_info[sub_resource_idx].dc)
3997 return WINED3DERR_INVALIDCALL;
4000 if (!(texture->flags & WINED3D_TEXTURE_GET_DC_LENIENT))
4001 texture->flags |= WINED3D_TEXTURE_DC_IN_USE;
4002 ++texture->resource.map_count;
4003 ++sub_resource->map_count;
4005 *dc = dc_info[sub_resource_idx].dc;
4006 TRACE("Returning dc %p.\n", *dc);
4008 return WINED3D_OK;
4011 HRESULT CDECL wined3d_texture_release_dc(struct wined3d_texture *texture, unsigned int sub_resource_idx, HDC dc)
4013 struct wined3d_device *device = texture->resource.device;
4014 struct wined3d_texture_sub_resource *sub_resource;
4015 struct wined3d_dc_info *dc_info;
4017 TRACE("texture %p, sub_resource_idx %u, dc %p.\n", texture, sub_resource_idx, dc);
4019 if (!(sub_resource = wined3d_texture_get_sub_resource(texture, sub_resource_idx)))
4020 return WINED3DERR_INVALIDCALL;
4022 if (texture->resource.type != WINED3D_RTYPE_TEXTURE_2D)
4024 WARN("Not supported on %s resources.\n", debug_d3dresourcetype(texture->resource.type));
4025 return WINED3DERR_INVALIDCALL;
4028 if (!(texture->flags & (WINED3D_TEXTURE_GET_DC_LENIENT | WINED3D_TEXTURE_DC_IN_USE)))
4029 return WINED3DERR_INVALIDCALL;
4031 if (!(dc_info = texture->dc_info) || dc_info[sub_resource_idx].dc != dc)
4033 WARN("Application tries to release invalid DC %p, sub-resource DC is %p.\n",
4034 dc, dc_info ? dc_info[sub_resource_idx].dc : NULL);
4035 return WINED3DERR_INVALIDCALL;
4038 if (!(texture->resource.usage & WINED3DUSAGE_OWNDC))
4040 struct wined3d_texture_idx texture_idx = {texture, sub_resource_idx};
4042 wined3d_cs_destroy_object(device->cs, wined3d_texture_destroy_dc, &texture_idx);
4043 wined3d_cs_finish(device->cs, WINED3D_CS_QUEUE_DEFAULT);
4046 --sub_resource->map_count;
4047 if (!--texture->resource.map_count && texture->update_map_binding)
4048 wined3d_texture_update_map_binding(texture);
4049 if (!(texture->flags & WINED3D_TEXTURE_GET_DC_LENIENT))
4050 texture->flags &= ~WINED3D_TEXTURE_DC_IN_USE;
4052 return WINED3D_OK;
4055 void wined3d_texture_upload_from_texture(struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx,
4056 unsigned int dst_x, unsigned int dst_y, unsigned int dst_z, struct wined3d_texture *src_texture,
4057 unsigned int src_sub_resource_idx, const struct wined3d_box *src_box)
4059 unsigned int src_row_pitch, src_slice_pitch;
4060 unsigned int update_w, update_h, update_d;
4061 unsigned int src_level, dst_level;
4062 struct wined3d_context *context;
4063 struct wined3d_bo_address data;
4065 TRACE("dst_texture %p, dst_sub_resource_idx %u, dst_x %u, dst_y %u, dst_z %u, "
4066 "src_texture %p, src_sub_resource_idx %u, src_box %s.\n",
4067 dst_texture, dst_sub_resource_idx, dst_x, dst_y, dst_z,
4068 src_texture, src_sub_resource_idx, debug_box(src_box));
4070 context = context_acquire(dst_texture->resource.device, NULL, 0);
4072 /* Only load the sub-resource for partial updates. For newly allocated
4073 * textures the texture wouldn't be the current location, and we'd upload
4074 * zeroes just to overwrite them again. */
4075 update_w = src_box->right - src_box->left;
4076 update_h = src_box->bottom - src_box->top;
4077 update_d = src_box->back - src_box->front;
4078 dst_level = dst_sub_resource_idx % dst_texture->level_count;
4079 if (update_w == wined3d_texture_get_level_width(dst_texture, dst_level)
4080 && update_h == wined3d_texture_get_level_height(dst_texture, dst_level)
4081 && update_d == wined3d_texture_get_level_depth(dst_texture, dst_level))
4082 wined3d_texture_prepare_location(dst_texture, dst_sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB);
4083 else
4084 wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB);
4086 src_level = src_sub_resource_idx % src_texture->level_count;
4087 wined3d_texture_get_memory(src_texture, src_sub_resource_idx, &data,
4088 src_texture->sub_resources[src_sub_resource_idx].locations);
4089 wined3d_texture_get_pitch(src_texture, src_level, &src_row_pitch, &src_slice_pitch);
4091 dst_texture->texture_ops->texture_upload_data(context, wined3d_const_bo_address(&data),
4092 src_texture->resource.format, src_box, src_row_pitch, src_slice_pitch, dst_texture,
4093 dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB, dst_x, dst_y, dst_z);
4095 context_release(context);
4097 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB);
4098 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB);
4101 /* Partial downloads are not supported. */
4102 void wined3d_texture_download_from_texture(struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx,
4103 struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx)
4105 unsigned int src_level, dst_level, dst_row_pitch, dst_slice_pitch;
4106 unsigned int dst_location = dst_texture->resource.map_binding;
4107 struct wined3d_context *context;
4108 struct wined3d_bo_address data;
4109 struct wined3d_box src_box;
4110 unsigned int src_location;
4112 context = context_acquire(src_texture->resource.device, NULL, 0);
4114 wined3d_texture_prepare_location(dst_texture, dst_sub_resource_idx, context, dst_location);
4115 wined3d_texture_get_memory(dst_texture, dst_sub_resource_idx, &data, dst_location);
4117 if (src_texture->sub_resources[src_sub_resource_idx].locations & WINED3D_LOCATION_TEXTURE_RGB)
4118 src_location = WINED3D_LOCATION_TEXTURE_RGB;
4119 else
4120 src_location = WINED3D_LOCATION_TEXTURE_SRGB;
4121 src_level = src_sub_resource_idx % src_texture->level_count;
4122 wined3d_texture_get_level_box(src_texture, src_level, &src_box);
4124 dst_level = dst_sub_resource_idx % dst_texture->level_count;
4125 wined3d_texture_get_pitch(dst_texture, dst_level, &dst_row_pitch, &dst_slice_pitch);
4127 src_texture->texture_ops->texture_download_data(context, src_texture, src_sub_resource_idx, src_location,
4128 &src_box, &data, dst_texture->resource.format, 0, 0, 0, dst_row_pitch, dst_slice_pitch);
4130 context_release(context);
4132 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, dst_location);
4133 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~dst_location);
4136 static void wined3d_texture_no3d_upload_data(struct wined3d_context *context,
4137 const struct wined3d_const_bo_address *src_bo_addr, const struct wined3d_format *src_format,
4138 const struct wined3d_box *src_box, unsigned int src_row_pitch, unsigned int src_slice_pitch,
4139 struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, unsigned int dst_location,
4140 unsigned int dst_x, unsigned int dst_y, unsigned int dst_z)
4142 FIXME("Not implemented.\n");
4145 static void wined3d_texture_no3d_download_data(struct wined3d_context *context,
4146 struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx, unsigned int src_location,
4147 const struct wined3d_box *src_box, const struct wined3d_bo_address *dst_bo_addr,
4148 const struct wined3d_format *dst_format, unsigned int dst_x, unsigned int dst_y, unsigned int dst_z,
4149 unsigned int dst_row_pitch, unsigned int dst_slice_pitch)
4151 FIXME("Not implemented.\n");
4154 static BOOL wined3d_texture_no3d_prepare_location(struct wined3d_texture *texture,
4155 unsigned int sub_resource_idx, struct wined3d_context *context, unsigned int location)
4157 switch (location)
4159 case WINED3D_LOCATION_SYSMEM:
4160 return wined3d_resource_prepare_sysmem(&texture->resource);
4162 case WINED3D_LOCATION_USER_MEMORY:
4163 if (!texture->user_memory)
4164 ERR("Preparing WINED3D_LOCATION_USER_MEMORY, but texture->user_memory is NULL.\n");
4165 return TRUE;
4167 default:
4168 FIXME("Unhandled location %s.\n", wined3d_debug_location(location));
4169 return FALSE;
4173 static BOOL wined3d_texture_no3d_load_location(struct wined3d_texture *texture,
4174 unsigned int sub_resource_idx, struct wined3d_context *context, DWORD location)
4176 TRACE("texture %p, sub_resource_idx %u, context %p, location %s.\n",
4177 texture, sub_resource_idx, context, wined3d_debug_location(location));
4179 if (location == WINED3D_LOCATION_USER_MEMORY || location == WINED3D_LOCATION_SYSMEM)
4180 return TRUE;
4182 ERR("Unhandled location %s.\n", wined3d_debug_location(location));
4184 return FALSE;
4187 static void wined3d_texture_no3d_unload_location(struct wined3d_texture *texture,
4188 struct wined3d_context *context, unsigned int location)
4190 TRACE("texture %p, context %p, location %s.\n", texture, context, wined3d_debug_location(location));
4193 static const struct wined3d_texture_ops wined3d_texture_no3d_ops =
4195 wined3d_texture_no3d_prepare_location,
4196 wined3d_texture_no3d_load_location,
4197 wined3d_texture_no3d_unload_location,
4198 wined3d_texture_no3d_upload_data,
4199 wined3d_texture_no3d_download_data,
4202 HRESULT wined3d_texture_no3d_init(struct wined3d_texture *texture_no3d, struct wined3d_device *device,
4203 const struct wined3d_resource_desc *desc, unsigned int layer_count, unsigned int level_count,
4204 uint32_t flags, void *parent, const struct wined3d_parent_ops *parent_ops)
4206 TRACE("texture_no3d %p, device %p, desc %p, layer_count %u, "
4207 "level_count %u, flags %#x, parent %p, parent_ops %p.\n",
4208 texture_no3d, device, desc, layer_count,
4209 level_count, flags, parent, parent_ops);
4211 return wined3d_texture_init(texture_no3d, desc, layer_count, level_count,
4212 flags, device, parent, parent_ops, &texture_no3d[1], &wined3d_texture_no3d_ops);
4215 static void wined3d_texture_vk_upload_data(struct wined3d_context *context,
4216 const struct wined3d_const_bo_address *src_bo_addr, const struct wined3d_format *src_format,
4217 const struct wined3d_box *src_box, unsigned int src_row_pitch, unsigned int src_slice_pitch,
4218 struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, unsigned int dst_location,
4219 unsigned int dst_x, unsigned int dst_y, unsigned int dst_z)
4221 struct wined3d_texture_vk *dst_texture_vk = wined3d_texture_vk(dst_texture);
4222 struct wined3d_context_vk *context_vk = wined3d_context_vk(context);
4223 unsigned int dst_level, dst_row_pitch, dst_slice_pitch;
4224 struct wined3d_texture_sub_resource *sub_resource;
4225 struct wined3d_bo_address staging_bo_addr;
4226 const struct wined3d_vk_info *vk_info;
4227 VkCommandBuffer vk_command_buffer;
4228 struct wined3d_bo_vk staging_bo;
4229 VkImageAspectFlags aspect_mask;
4230 size_t src_offset, dst_offset;
4231 struct wined3d_range range;
4232 VkBufferImageCopy region;
4233 void *map_ptr;
4235 TRACE("context %p, src_bo_addr %s, src_format %s, src_box %s, src_row_pitch %u, src_slice_pitch %u, "
4236 "dst_texture %p, dst_sub_resource_idx %u, dst_location %s, dst_x %u, dst_y %u, dst_z %u.\n",
4237 context, debug_const_bo_address(src_bo_addr), debug_d3dformat(src_format->id), debug_box(src_box),
4238 src_row_pitch, src_slice_pitch, dst_texture, dst_sub_resource_idx,
4239 wined3d_debug_location(dst_location), dst_x, dst_y, dst_z);
4241 if (src_bo_addr->buffer_object)
4243 FIXME("Unhandled buffer object %#lx.\n", src_bo_addr->buffer_object);
4244 return;
4247 if (src_format->id != dst_texture->resource.format->id)
4249 FIXME("Unhandled format conversion (%s -> %s).\n",
4250 debug_d3dformat(src_format->id),
4251 debug_d3dformat(dst_texture->resource.format->id));
4252 return;
4255 dst_level = dst_sub_resource_idx % dst_texture->level_count;
4256 wined3d_texture_get_pitch(dst_texture, dst_level, &dst_row_pitch, &dst_slice_pitch);
4257 if (dst_texture->resource.type == WINED3D_RTYPE_TEXTURE_1D)
4258 src_row_pitch = dst_row_pitch = 0;
4259 if (dst_texture->resource.type != WINED3D_RTYPE_TEXTURE_3D)
4260 src_slice_pitch = dst_slice_pitch = 0;
4262 if (dst_location != WINED3D_LOCATION_TEXTURE_RGB)
4264 FIXME("Unhandled location %s.\n", wined3d_debug_location(dst_location));
4265 return;
4268 if (wined3d_resource_get_sample_count(&dst_texture_vk->t.resource) > 1)
4270 FIXME("Not supported for multisample textures.\n");
4271 return;
4274 aspect_mask = vk_aspect_mask_from_format(dst_texture->resource.format);
4275 if (wined3d_popcount(aspect_mask) > 1)
4277 FIXME("Unhandled multi-aspect format %s.\n", debug_d3dformat(dst_texture->resource.format->id));
4278 return;
4281 sub_resource = &dst_texture_vk->t.sub_resources[dst_sub_resource_idx];
4282 vk_info = context_vk->vk_info;
4284 src_offset = src_box->front * src_slice_pitch
4285 + (src_box->top / src_format->block_height) * src_row_pitch
4286 + (src_box->left / src_format->block_width) * src_format->block_byte_count;
4287 dst_offset = dst_z * src_slice_pitch
4288 + (dst_y / src_format->block_height) * src_row_pitch
4289 + (dst_x / src_format->block_width) * src_format->block_byte_count;
4291 if (!wined3d_context_vk_create_bo(context_vk, sub_resource->size,
4292 VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &staging_bo))
4294 ERR("Failed to create staging bo.\n");
4295 return;
4298 staging_bo_addr.buffer_object = (uintptr_t)&staging_bo;
4299 staging_bo_addr.addr = NULL;
4300 if (!(map_ptr = wined3d_context_map_bo_address(context, &staging_bo_addr,
4301 sub_resource->size, 0, WINED3D_MAP_DISCARD | WINED3D_MAP_WRITE)))
4303 ERR("Failed to map staging bo.\n");
4304 wined3d_context_vk_destroy_bo(context_vk, &staging_bo);
4305 return;
4308 wined3d_format_copy_data(src_format, src_bo_addr->addr + src_offset, src_row_pitch, src_slice_pitch,
4309 (uint8_t *)map_ptr + dst_offset, dst_row_pitch, dst_slice_pitch, src_box->right - src_box->left,
4310 src_box->bottom - src_box->top, src_box->back - src_box->front);
4312 range.offset = 0;
4313 range.size = sub_resource->size;
4314 wined3d_context_unmap_bo_address(context, &staging_bo_addr, 0, 1, &range);
4316 if (!(vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk)))
4318 ERR("Failed to get command buffer.\n");
4319 return;
4322 wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
4323 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
4324 vk_access_mask_from_bind_flags(dst_texture_vk->t.resource.bind_flags),
4325 VK_ACCESS_TRANSFER_WRITE_BIT,
4326 dst_texture_vk->layout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
4327 dst_texture_vk->vk_image, aspect_mask);
4329 region.bufferOffset = dst_offset;
4330 region.bufferRowLength = (dst_row_pitch / src_format->block_byte_count) * src_format->block_width;
4331 if (dst_row_pitch)
4332 region.bufferImageHeight = (dst_slice_pitch / dst_row_pitch) * src_format->block_height;
4333 else
4334 region.bufferImageHeight = 1;
4335 region.imageSubresource.aspectMask = aspect_mask;
4336 region.imageSubresource.mipLevel = dst_level;
4337 region.imageSubresource.baseArrayLayer = dst_sub_resource_idx / dst_texture_vk->t.level_count;
4338 region.imageSubresource.layerCount = 1;
4339 region.imageOffset.x = dst_x;
4340 region.imageOffset.y = dst_y;
4341 region.imageOffset.z = dst_z;
4342 region.imageExtent.width = src_box->right - src_box->left;
4343 region.imageExtent.height = src_box->bottom - src_box->top;
4344 region.imageExtent.depth = src_box->back - src_box->front;
4346 VK_CALL(vkCmdCopyBufferToImage(vk_command_buffer, staging_bo.vk_buffer,
4347 dst_texture_vk->vk_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region));
4349 wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
4350 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
4351 VK_ACCESS_TRANSFER_WRITE_BIT,
4352 vk_access_mask_from_bind_flags(dst_texture_vk->t.resource.bind_flags),
4353 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, dst_texture_vk->layout,
4354 dst_texture_vk->vk_image, aspect_mask);
4355 dst_texture_vk->command_buffer_id = context_vk->current_command_buffer.id;
4356 staging_bo.command_buffer_id = context_vk->current_command_buffer.id;
4357 wined3d_context_vk_destroy_bo(context_vk, &staging_bo);
4360 static void wined3d_texture_vk_download_data(struct wined3d_context *context,
4361 struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx, unsigned int src_location,
4362 const struct wined3d_box *src_box, const struct wined3d_bo_address *dst_bo_addr,
4363 const struct wined3d_format *dst_format, unsigned int dst_x, unsigned int dst_y, unsigned int dst_z,
4364 unsigned int dst_row_pitch, unsigned int dst_slice_pitch)
4366 FIXME("Not implemented.\n");
4369 static BOOL wined3d_texture_vk_load_texture(struct wined3d_texture_vk *texture_vk,
4370 unsigned int sub_resource_idx, struct wined3d_context *context)
4372 struct wined3d_texture_sub_resource *sub_resource;
4373 unsigned int level, row_pitch, slice_pitch;
4374 struct wined3d_bo_address data;
4375 struct wined3d_box src_box;
4377 sub_resource = &texture_vk->t.sub_resources[sub_resource_idx];
4378 if (!(sub_resource->locations & WINED3D_LOCATION_SYSMEM))
4380 ERR("Unimplemented load from %s.\n", wined3d_debug_location(sub_resource->locations));
4381 return FALSE;
4384 level = sub_resource_idx % texture_vk->t.level_count;
4385 wined3d_texture_get_memory(&texture_vk->t, sub_resource_idx, &data, WINED3D_LOCATION_SYSMEM);
4386 wined3d_texture_get_level_box(&texture_vk->t, level, &src_box);
4387 wined3d_texture_get_pitch(&texture_vk->t, level, &row_pitch, &slice_pitch);
4388 wined3d_texture_vk_upload_data(context, wined3d_const_bo_address(&data), texture_vk->t.resource.format,
4389 &src_box, row_pitch, slice_pitch, &texture_vk->t, sub_resource_idx,
4390 WINED3D_LOCATION_TEXTURE_RGB, 0, 0, 0);
4392 return TRUE;
4395 static BOOL wined3d_texture_vk_prepare_texture(struct wined3d_texture_vk *texture_vk,
4396 struct wined3d_context_vk *context_vk)
4398 const struct wined3d_format_vk *format_vk;
4399 VkMemoryRequirements memory_requirements;
4400 const struct wined3d_vk_info *vk_info;
4401 struct wined3d_adapter_vk *adapter_vk;
4402 struct wined3d_device_vk *device_vk;
4403 struct wined3d_resource *resource;
4404 VkCommandBuffer vk_command_buffer;
4405 VkImageCreateInfo create_info;
4406 unsigned int memory_type_idx;
4407 VkResult vr;
4409 if (texture_vk->t.flags & WINED3D_TEXTURE_RGB_ALLOCATED)
4410 return TRUE;
4412 if (!(vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk)))
4414 ERR("Failed to get command buffer.\n");
4415 return FALSE;
4418 resource = &texture_vk->t.resource;
4419 device_vk = wined3d_device_vk(resource->device);
4420 adapter_vk = wined3d_adapter_vk(device_vk->d.adapter);
4421 format_vk = wined3d_format_vk(resource->format);
4422 vk_info = context_vk->vk_info;
4424 create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
4425 create_info.pNext = NULL;
4427 create_info.flags = 0;
4428 if (wined3d_format_is_typeless(&format_vk->f))
4429 create_info.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
4431 switch (resource->type)
4433 case WINED3D_RTYPE_TEXTURE_1D:
4434 create_info.imageType = VK_IMAGE_TYPE_1D;
4435 break;
4436 case WINED3D_RTYPE_TEXTURE_2D:
4437 create_info.imageType = VK_IMAGE_TYPE_2D;
4438 if (texture_vk->t.layer_count >= 6 && resource->width == resource->height)
4439 create_info.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
4440 break;
4441 case WINED3D_RTYPE_TEXTURE_3D:
4442 create_info.imageType = VK_IMAGE_TYPE_3D;
4443 if (resource->bind_flags & (WINED3D_BIND_RENDER_TARGET | WINED3D_BIND_UNORDERED_ACCESS))
4444 create_info.flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;
4445 break;
4446 default:
4447 ERR("Invalid resource type %s.\n", debug_d3dresourcetype(resource->type));
4448 create_info.imageType = VK_IMAGE_TYPE_2D;
4449 break;
4452 create_info.format = format_vk->vk_format;
4453 create_info.extent.width = resource->width;
4454 create_info.extent.height = resource->height;
4455 create_info.extent.depth = resource->depth;
4456 create_info.mipLevels = texture_vk->t.level_count;
4457 create_info.arrayLayers = texture_vk->t.layer_count;
4458 create_info.samples = max(1, wined3d_resource_get_sample_count(resource));
4459 create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
4461 create_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
4462 if (resource->bind_flags & WINED3D_BIND_SHADER_RESOURCE)
4463 create_info.usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
4464 if (resource->bind_flags & WINED3D_BIND_RENDER_TARGET)
4465 create_info.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
4466 if (resource->bind_flags & WINED3D_BIND_DEPTH_STENCIL)
4467 create_info.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
4468 if (resource->bind_flags & WINED3D_BIND_UNORDERED_ACCESS)
4469 create_info.usage |= VK_IMAGE_USAGE_STORAGE_BIT;
4471 texture_vk->layout = VK_IMAGE_LAYOUT_GENERAL;
4472 if (wined3d_popcount(resource->bind_flags == 1))
4474 switch (resource->bind_flags)
4476 case WINED3D_BIND_RENDER_TARGET:
4477 texture_vk->layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
4478 break;
4480 case WINED3D_BIND_DEPTH_STENCIL:
4481 texture_vk->layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
4482 break;
4484 case WINED3D_BIND_SHADER_RESOURCE:
4485 texture_vk->layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
4486 break;
4488 default:
4489 break;
4493 create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
4494 create_info.queueFamilyIndexCount = 0;
4495 create_info.pQueueFamilyIndices = NULL;
4496 create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
4497 if ((vr = VK_CALL(vkCreateImage(device_vk->vk_device, &create_info, NULL, &texture_vk->vk_image))) < 0)
4499 ERR("Failed to create Vulkan image, vr %s.\n", wined3d_debug_vkresult(vr));
4500 return FALSE;
4503 VK_CALL(vkGetImageMemoryRequirements(device_vk->vk_device, texture_vk->vk_image, &memory_requirements));
4505 memory_type_idx = wined3d_adapter_vk_get_memory_type_index(adapter_vk,
4506 memory_requirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
4507 if (memory_type_idx == ~0u)
4509 ERR("Failed to find suitable memory type.\n");
4510 VK_CALL(vkDestroyImage(device_vk->vk_device, texture_vk->vk_image, NULL));
4511 texture_vk->vk_image = VK_NULL_HANDLE;
4512 return FALSE;
4515 texture_vk->memory = wined3d_context_vk_allocate_memory(context_vk,
4516 memory_type_idx, memory_requirements.size, &texture_vk->vk_memory);
4517 if (!texture_vk->vk_memory)
4519 ERR("Failed to allocate image memory.\n");
4520 VK_CALL(vkDestroyImage(device_vk->vk_device, texture_vk->vk_image, NULL));
4521 texture_vk->vk_image = VK_NULL_HANDLE;
4522 return FALSE;
4525 if ((vr = VK_CALL(vkBindImageMemory(device_vk->vk_device, texture_vk->vk_image,
4526 texture_vk->vk_memory, texture_vk->memory ? texture_vk->memory->offset : 0))) < 0)
4528 WARN("Failed to bind memory, vr %s.\n", wined3d_debug_vkresult(vr));
4529 if (texture_vk->memory)
4530 wined3d_allocator_block_free(texture_vk->memory);
4531 else
4532 VK_CALL(vkFreeMemory(device_vk->vk_device, texture_vk->vk_memory, NULL));
4533 texture_vk->vk_memory = VK_NULL_HANDLE;
4534 VK_CALL(vkDestroyImage(device_vk->vk_device, texture_vk->vk_image, NULL));
4535 texture_vk->vk_image = VK_NULL_HANDLE;
4536 return FALSE;
4539 texture_vk->command_buffer_id = context_vk->current_command_buffer.id;
4540 wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
4541 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
4542 0, 0,
4543 VK_IMAGE_LAYOUT_UNDEFINED, texture_vk->layout,
4544 texture_vk->vk_image, vk_aspect_mask_from_format(&format_vk->f));
4546 texture_vk->t.flags |= WINED3D_TEXTURE_RGB_ALLOCATED;
4548 TRACE("Created image 0x%s, memory 0x%s for texture %p.\n",
4549 wine_dbgstr_longlong(texture_vk->vk_image), wine_dbgstr_longlong(texture_vk->vk_memory), texture_vk);
4551 return TRUE;
4554 static BOOL wined3d_texture_vk_prepare_location(struct wined3d_texture *texture,
4555 unsigned int sub_resource_idx, struct wined3d_context *context, unsigned int location)
4557 switch (location)
4559 case WINED3D_LOCATION_SYSMEM:
4560 return wined3d_resource_prepare_sysmem(&texture->resource);
4562 case WINED3D_LOCATION_USER_MEMORY:
4563 if (!texture->user_memory)
4564 ERR("Preparing WINED3D_LOCATION_USER_MEMORY, but texture->user_memory is NULL.\n");
4565 return TRUE;
4567 case WINED3D_LOCATION_TEXTURE_RGB:
4568 return wined3d_texture_vk_prepare_texture(wined3d_texture_vk(texture), wined3d_context_vk(context));
4570 default:
4571 FIXME("Unhandled location %s.\n", wined3d_debug_location(location));
4572 return FALSE;
4576 static BOOL wined3d_texture_vk_load_location(struct wined3d_texture *texture,
4577 unsigned int sub_resource_idx, struct wined3d_context *context, DWORD location)
4579 if (!wined3d_texture_vk_prepare_location(texture, sub_resource_idx, context, location))
4580 return FALSE;
4582 switch (location)
4584 case WINED3D_LOCATION_TEXTURE_RGB:
4585 return wined3d_texture_vk_load_texture(wined3d_texture_vk(texture), sub_resource_idx, context);
4587 default:
4588 FIXME("Unimplemented location %s.\n", wined3d_debug_location(location));
4589 return FALSE;
4593 static void wined3d_texture_vk_unload_location(struct wined3d_texture *texture,
4594 struct wined3d_context *context, unsigned int location)
4596 struct wined3d_texture_vk *texture_vk = wined3d_texture_vk(texture);
4597 struct wined3d_context_vk *context_vk = wined3d_context_vk(context);
4599 TRACE("texture %p, context %p, location %s.\n", texture, context, wined3d_debug_location(location));
4601 switch (location)
4603 case WINED3D_LOCATION_TEXTURE_RGB:
4604 if (texture_vk->vk_image)
4606 wined3d_context_vk_destroy_image(context_vk, texture_vk->vk_image, texture_vk->command_buffer_id);
4607 texture_vk->vk_image = VK_NULL_HANDLE;
4608 if (texture_vk->memory)
4609 wined3d_context_vk_destroy_allocator_block(context_vk,
4610 texture_vk->memory, texture_vk->command_buffer_id);
4611 else
4612 wined3d_context_vk_destroy_memory(context_vk,
4613 texture_vk->vk_memory, texture_vk->command_buffer_id);
4614 texture_vk->vk_memory = VK_NULL_HANDLE;
4615 texture_vk->memory = NULL;
4617 break;
4619 case WINED3D_LOCATION_BUFFER:
4620 case WINED3D_LOCATION_TEXTURE_SRGB:
4621 case WINED3D_LOCATION_RB_MULTISAMPLE:
4622 case WINED3D_LOCATION_RB_RESOLVED:
4623 break;
4625 default:
4626 ERR("Unhandled location %s.\n", wined3d_debug_location(location));
4627 break;
4631 static const struct wined3d_texture_ops wined3d_texture_vk_ops =
4633 wined3d_texture_vk_prepare_location,
4634 wined3d_texture_vk_load_location,
4635 wined3d_texture_vk_unload_location,
4636 wined3d_texture_vk_upload_data,
4637 wined3d_texture_vk_download_data,
4640 HRESULT wined3d_texture_vk_init(struct wined3d_texture_vk *texture_vk, struct wined3d_device *device,
4641 const struct wined3d_resource_desc *desc, unsigned int layer_count, unsigned int level_count,
4642 uint32_t flags, void *parent, const struct wined3d_parent_ops *parent_ops)
4644 TRACE("texture_vk %p, device %p, desc %p, layer_count %u, "
4645 "level_count %u, flags %#x, parent %p, parent_ops %p.\n",
4646 texture_vk, device, desc, layer_count,
4647 level_count, flags, parent, parent_ops);
4649 return wined3d_texture_init(&texture_vk->t, desc, layer_count, level_count,
4650 flags, device, parent, parent_ops, &texture_vk[1], &wined3d_texture_vk_ops);