wined3d: Merge wined3d_texture_upload_data() and wined3d_texture_gl_upload_data().
[wine.git] / dlls / wined3d / texture.c
blob1f9e5817699b7a621ee2d4d59d9fe09622e48448
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 static BOOL wined3d_texture_copy_sysmem_location(struct wined3d_texture *texture,
344 unsigned int sub_resource_idx, struct wined3d_context *context, DWORD location)
346 unsigned int size = texture->sub_resources[sub_resource_idx].size;
347 struct wined3d_device *device = texture->resource.device;
348 const struct wined3d_gl_info *gl_info;
349 struct wined3d_bo_address dst, src;
351 if (!wined3d_texture_prepare_location(texture, sub_resource_idx, context, location))
352 return FALSE;
354 wined3d_texture_get_memory(texture, sub_resource_idx, &dst, location);
355 wined3d_texture_get_memory(texture, sub_resource_idx, &src,
356 texture->sub_resources[sub_resource_idx].locations);
358 if (dst.buffer_object)
360 context = context_acquire(device, NULL, 0);
361 gl_info = wined3d_context_gl(context)->gl_info;
362 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, dst.buffer_object));
363 GL_EXTCALL(glBufferSubData(GL_PIXEL_UNPACK_BUFFER, 0, size, src.addr));
364 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));
365 checkGLcall("PBO upload");
366 context_release(context);
367 return TRUE;
370 if (src.buffer_object)
372 context = context_acquire(device, NULL, 0);
373 gl_info = wined3d_context_gl(context)->gl_info;
374 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, src.buffer_object));
375 GL_EXTCALL(glGetBufferSubData(GL_PIXEL_PACK_BUFFER, 0, size, dst.addr));
376 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
377 checkGLcall("PBO download");
378 context_release(context);
379 return TRUE;
382 memcpy(dst.addr, src.addr, size);
383 return TRUE;
386 /* Context activation is done by the caller. Context may be NULL in
387 * WINED3D_NO3D mode. */
388 BOOL wined3d_texture_load_location(struct wined3d_texture *texture,
389 unsigned int sub_resource_idx, struct wined3d_context *context, DWORD location)
391 DWORD current = texture->sub_resources[sub_resource_idx].locations;
392 BOOL ret;
394 TRACE("texture %p, sub_resource_idx %u, context %p, location %s.\n",
395 texture, sub_resource_idx, context, wined3d_debug_location(location));
397 TRACE("Current resource location %s.\n", wined3d_debug_location(current));
399 if (current & location)
401 TRACE("Location %s is already up to date.\n", wined3d_debug_location(location));
402 return TRUE;
405 if (WARN_ON(d3d))
407 DWORD required_access = wined3d_resource_access_from_location(location);
408 if ((texture->resource.access & required_access) != required_access)
409 WARN("Operation requires %#x access, but texture only has %#x.\n",
410 required_access, texture->resource.access);
413 if (current & WINED3D_LOCATION_DISCARDED)
415 TRACE("Sub-resource previously discarded, nothing to do.\n");
416 if (!wined3d_texture_prepare_location(texture, sub_resource_idx, context, location))
417 return FALSE;
418 wined3d_texture_validate_location(texture, sub_resource_idx, location);
419 wined3d_texture_invalidate_location(texture, sub_resource_idx, WINED3D_LOCATION_DISCARDED);
420 return TRUE;
423 if (!current)
425 ERR("Sub-resource %u of texture %p does not have any up to date location.\n",
426 sub_resource_idx, texture);
427 wined3d_texture_validate_location(texture, sub_resource_idx, WINED3D_LOCATION_DISCARDED);
428 return wined3d_texture_load_location(texture, sub_resource_idx, context, location);
431 if ((location & wined3d_texture_sysmem_locations) && (current & wined3d_texture_sysmem_locations))
432 ret = wined3d_texture_copy_sysmem_location(texture, sub_resource_idx, context, location);
433 else
434 ret = texture->texture_ops->texture_load_location(texture, sub_resource_idx, context, location);
436 if (ret)
437 wined3d_texture_validate_location(texture, sub_resource_idx, location);
439 return ret;
442 void wined3d_texture_get_memory(struct wined3d_texture *texture, unsigned int sub_resource_idx,
443 struct wined3d_bo_address *data, DWORD locations)
445 struct wined3d_texture_sub_resource *sub_resource;
447 TRACE("texture %p, sub_resource_idx %u, data %p, locations %s.\n",
448 texture, sub_resource_idx, data, wined3d_debug_location(locations));
450 sub_resource = &texture->sub_resources[sub_resource_idx];
451 if (locations & WINED3D_LOCATION_BUFFER)
453 data->addr = NULL;
454 data->buffer_object = sub_resource->buffer_object;
455 return;
457 if (locations & WINED3D_LOCATION_USER_MEMORY)
459 data->addr = texture->user_memory;
460 data->buffer_object = 0;
461 return;
463 if (locations & WINED3D_LOCATION_SYSMEM)
465 data->addr = texture->resource.heap_memory;
466 data->addr += sub_resource->offset;
467 data->buffer_object = 0;
468 return;
471 ERR("Unexpected locations %s.\n", wined3d_debug_location(locations));
472 data->addr = NULL;
473 data->buffer_object = 0;
476 /* Context activation is done by the caller. */
477 static void wined3d_texture_remove_buffer_object(struct wined3d_texture *texture,
478 unsigned int sub_resource_idx, const struct wined3d_gl_info *gl_info)
480 GLuint *buffer_object = &texture->sub_resources[sub_resource_idx].buffer_object;
482 GL_EXTCALL(glDeleteBuffers(1, buffer_object));
483 checkGLcall("glDeleteBuffers");
485 TRACE("Deleted buffer object %u for texture %p, sub-resource %u.\n",
486 *buffer_object, texture, sub_resource_idx);
488 wined3d_texture_invalidate_location(texture, sub_resource_idx, WINED3D_LOCATION_BUFFER);
489 *buffer_object = 0;
492 static void wined3d_texture_update_map_binding(struct wined3d_texture *texture)
494 unsigned int sub_count = texture->level_count * texture->layer_count;
495 struct wined3d_device *device = texture->resource.device;
496 DWORD map_binding = texture->update_map_binding;
497 struct wined3d_context *context = NULL;
498 unsigned int i;
500 if (device->d3d_initialized)
501 context = context_acquire(device, NULL, 0);
503 for (i = 0; i < sub_count; ++i)
505 if (texture->sub_resources[i].locations == texture->resource.map_binding
506 && !wined3d_texture_load_location(texture, i, context, map_binding))
507 ERR("Failed to load location %s.\n", wined3d_debug_location(map_binding));
508 if (texture->resource.map_binding == WINED3D_LOCATION_BUFFER)
509 wined3d_texture_remove_buffer_object(texture, i, wined3d_context_gl(context)->gl_info);
512 if (context)
513 context_release(context);
515 texture->resource.map_binding = map_binding;
516 texture->update_map_binding = 0;
519 void wined3d_texture_set_map_binding(struct wined3d_texture *texture, DWORD map_binding)
521 texture->update_map_binding = map_binding;
522 if (!texture->resource.map_count)
523 wined3d_texture_update_map_binding(texture);
526 /* A GL context is provided by the caller */
527 static void gltexture_delete(struct wined3d_device *device, const struct wined3d_gl_info *gl_info,
528 struct gl_texture *tex)
530 context_gl_resource_released(device, tex->name, FALSE);
531 gl_info->gl_ops.gl.p_glDeleteTextures(1, &tex->name);
532 tex->name = 0;
535 /* Context activation is done by the caller. */
536 /* The caller is responsible for binding the correct texture. */
537 static void wined3d_texture_gl_allocate_mutable_storage(struct wined3d_texture_gl *texture_gl,
538 GLenum gl_internal_format, const struct wined3d_format_gl *format,
539 const struct wined3d_gl_info *gl_info)
541 unsigned int level, level_count, layer, layer_count;
542 GLsizei width, height, depth;
543 GLenum target;
545 level_count = texture_gl->t.level_count;
546 if (texture_gl->target == GL_TEXTURE_1D_ARRAY || texture_gl->target == GL_TEXTURE_2D_ARRAY)
547 layer_count = 1;
548 else
549 layer_count = texture_gl->t.layer_count;
551 for (layer = 0; layer < layer_count; ++layer)
553 target = wined3d_texture_gl_get_sub_resource_target(texture_gl, layer * level_count);
555 for (level = 0; level < level_count; ++level)
557 width = wined3d_texture_get_level_pow2_width(&texture_gl->t, level);
558 height = wined3d_texture_get_level_pow2_height(&texture_gl->t, level);
559 if (texture_gl->t.resource.format_flags & WINED3DFMT_FLAG_HEIGHT_SCALE)
561 height *= format->f.height_scale.numerator;
562 height /= format->f.height_scale.denominator;
565 TRACE("texture_gl %p, layer %u, level %u, target %#x, width %u, height %u.\n",
566 texture_gl, layer, level, target, width, height);
568 if (target == GL_TEXTURE_3D || target == GL_TEXTURE_2D_ARRAY)
570 depth = wined3d_texture_get_level_depth(&texture_gl->t, level);
571 GL_EXTCALL(glTexImage3D(target, level, gl_internal_format, width, height,
572 target == GL_TEXTURE_2D_ARRAY ? texture_gl->t.layer_count : depth, 0,
573 format->format, format->type, NULL));
574 checkGLcall("glTexImage3D");
576 else if (target == GL_TEXTURE_1D)
578 gl_info->gl_ops.gl.p_glTexImage1D(target, level, gl_internal_format,
579 width, 0, format->format, format->type, NULL);
581 else
583 gl_info->gl_ops.gl.p_glTexImage2D(target, level, gl_internal_format, width,
584 target == GL_TEXTURE_1D_ARRAY ? texture_gl->t.layer_count : height, 0,
585 format->format, format->type, NULL);
586 checkGLcall("glTexImage2D");
592 /* Context activation is done by the caller. */
593 /* The caller is responsible for binding the correct texture. */
594 static void wined3d_texture_gl_allocate_immutable_storage(struct wined3d_texture_gl *texture_gl,
595 GLenum gl_internal_format, const struct wined3d_gl_info *gl_info)
597 unsigned int samples = wined3d_resource_get_sample_count(&texture_gl->t.resource);
598 GLsizei height = wined3d_texture_get_level_pow2_height(&texture_gl->t, 0);
599 GLsizei width = wined3d_texture_get_level_pow2_width(&texture_gl->t, 0);
600 GLboolean standard_pattern = texture_gl->t.resource.multisample_type != WINED3D_MULTISAMPLE_NON_MASKABLE
601 && texture_gl->t.resource.multisample_quality == WINED3D_STANDARD_MULTISAMPLE_PATTERN;
603 switch (texture_gl->target)
605 case GL_TEXTURE_3D:
606 GL_EXTCALL(glTexStorage3D(texture_gl->target, texture_gl->t.level_count,
607 gl_internal_format, width, height, wined3d_texture_get_level_depth(&texture_gl->t, 0)));
608 break;
609 case GL_TEXTURE_2D_ARRAY:
610 GL_EXTCALL(glTexStorage3D(texture_gl->target, texture_gl->t.level_count,
611 gl_internal_format, width, height, texture_gl->t.layer_count));
612 break;
613 case GL_TEXTURE_2D_MULTISAMPLE:
614 GL_EXTCALL(glTexStorage2DMultisample(texture_gl->target, samples,
615 gl_internal_format, width, height, standard_pattern));
616 break;
617 case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
618 GL_EXTCALL(glTexStorage3DMultisample(texture_gl->target, samples,
619 gl_internal_format, width, height, texture_gl->t.layer_count, standard_pattern));
620 break;
621 case GL_TEXTURE_1D_ARRAY:
622 GL_EXTCALL(glTexStorage2D(texture_gl->target, texture_gl->t.level_count,
623 gl_internal_format, width, texture_gl->t.layer_count));
624 break;
625 case GL_TEXTURE_1D:
626 GL_EXTCALL(glTexStorage1D(texture_gl->target, texture_gl->t.level_count, gl_internal_format, width));
627 break;
628 default:
629 GL_EXTCALL(glTexStorage2D(texture_gl->target, texture_gl->t.level_count,
630 gl_internal_format, width, height));
631 break;
634 checkGLcall("allocate immutable storage");
637 void wined3d_texture_gl_unload_texture(struct wined3d_texture_gl *texture_gl)
639 struct wined3d_device *device = texture_gl->t.resource.device;
640 const struct wined3d_gl_info *gl_info = NULL;
641 struct wined3d_context *context = NULL;
643 if (texture_gl->t.resource.bind_count)
644 device_invalidate_state(device, STATE_SAMPLER(texture_gl->t.sampler));
646 if (texture_gl->texture_rgb.name || texture_gl->texture_srgb.name
647 || texture_gl->rb_multisample || texture_gl->rb_resolved)
649 context = context_acquire(device, NULL, 0);
650 gl_info = wined3d_context_gl(context)->gl_info;
653 if (texture_gl->texture_rgb.name)
654 gltexture_delete(device, gl_info, &texture_gl->texture_rgb);
656 if (texture_gl->texture_srgb.name)
657 gltexture_delete(device, gl_info, &texture_gl->texture_srgb);
659 if (texture_gl->rb_multisample)
661 TRACE("Deleting multisample renderbuffer %u.\n", texture_gl->rb_multisample);
662 context_gl_resource_released(device, texture_gl->rb_multisample, TRUE);
663 gl_info->fbo_ops.glDeleteRenderbuffers(1, &texture_gl->rb_multisample);
664 texture_gl->rb_multisample = 0;
667 if (texture_gl->rb_resolved)
669 TRACE("Deleting resolved renderbuffer %u.\n", texture_gl->rb_resolved);
670 context_gl_resource_released(device, texture_gl->rb_resolved, TRUE);
671 gl_info->fbo_ops.glDeleteRenderbuffers(1, &texture_gl->rb_resolved);
672 texture_gl->rb_resolved = 0;
675 if (context) context_release(context);
677 wined3d_texture_set_dirty(&texture_gl->t);
679 resource_unload(&texture_gl->t.resource);
682 void wined3d_texture_sub_resources_destroyed(struct wined3d_texture *texture)
684 unsigned int sub_count = texture->level_count * texture->layer_count;
685 struct wined3d_texture_sub_resource *sub_resource;
686 unsigned int i;
688 for (i = 0; i < sub_count; ++i)
690 sub_resource = &texture->sub_resources[i];
691 if (sub_resource->parent)
693 TRACE("sub-resource %u.\n", i);
694 sub_resource->parent_ops->wined3d_object_destroyed(sub_resource->parent);
695 sub_resource->parent = NULL;
700 static void wined3d_texture_create_dc(void *object)
702 const struct wined3d_texture_idx *idx = object;
703 struct wined3d_context *context = NULL;
704 unsigned int sub_resource_idx, level;
705 const struct wined3d_format *format;
706 unsigned int row_pitch, slice_pitch;
707 struct wined3d_texture *texture;
708 struct wined3d_dc_info *dc_info;
709 struct wined3d_bo_address data;
710 D3DKMT_CREATEDCFROMMEMORY desc;
711 struct wined3d_device *device;
712 NTSTATUS status;
714 TRACE("texture %p, sub_resource_idx %u.\n", idx->texture, idx->sub_resource_idx);
716 texture = idx->texture;
717 sub_resource_idx = idx->sub_resource_idx;
718 level = sub_resource_idx % texture->level_count;
719 device = texture->resource.device;
721 format = texture->resource.format;
722 if (!format->ddi_format)
724 WARN("Cannot create a DC for format %s.\n", debug_d3dformat(format->id));
725 return;
728 if (!texture->dc_info)
730 unsigned int sub_count = texture->level_count * texture->layer_count;
732 if (!(texture->dc_info = heap_calloc(sub_count, sizeof(*texture->dc_info))))
734 ERR("Failed to allocate DC info.\n");
735 return;
739 if (!(texture->sub_resources[sub_resource_idx].locations & texture->resource.map_binding))
741 context = context_acquire(device, NULL, 0);
742 wined3d_texture_load_location(texture, sub_resource_idx, context, texture->resource.map_binding);
744 wined3d_texture_invalidate_location(texture, sub_resource_idx, ~texture->resource.map_binding);
745 wined3d_texture_get_pitch(texture, level, &row_pitch, &slice_pitch);
746 wined3d_texture_get_memory(texture, sub_resource_idx, &data, texture->resource.map_binding);
747 if (data.buffer_object)
749 if (!context)
750 context = context_acquire(device, NULL, 0);
751 desc.pMemory = wined3d_context_map_bo_address(context, &data,
752 texture->sub_resources[sub_resource_idx].size,
753 GL_PIXEL_UNPACK_BUFFER, WINED3D_MAP_READ | WINED3D_MAP_WRITE);
755 else
757 desc.pMemory = data.addr;
760 if (context)
761 context_release(context);
763 desc.Format = format->ddi_format;
764 desc.Width = wined3d_texture_get_level_width(texture, level);
765 desc.Height = wined3d_texture_get_level_height(texture, level);
766 desc.Pitch = row_pitch;
767 desc.hDeviceDc = CreateCompatibleDC(NULL);
768 desc.pColorTable = NULL;
770 status = D3DKMTCreateDCFromMemory(&desc);
771 DeleteDC(desc.hDeviceDc);
772 if (status)
774 WARN("Failed to create DC, status %#x.\n", status);
775 return;
778 dc_info = &texture->dc_info[sub_resource_idx];
779 dc_info->dc = desc.hDc;
780 dc_info->bitmap = desc.hBitmap;
782 TRACE("Created DC %p, bitmap %p for texture %p, %u.\n", dc_info->dc, dc_info->bitmap, texture, sub_resource_idx);
785 static void wined3d_texture_destroy_dc(void *object)
787 const struct wined3d_texture_idx *idx = object;
788 D3DKMT_DESTROYDCFROMMEMORY destroy_desc;
789 struct wined3d_context *context;
790 struct wined3d_texture *texture;
791 struct wined3d_dc_info *dc_info;
792 struct wined3d_bo_address data;
793 unsigned int sub_resource_idx;
794 struct wined3d_device *device;
795 NTSTATUS status;
797 texture = idx->texture;
798 sub_resource_idx = idx->sub_resource_idx;
799 device = texture->resource.device;
800 dc_info = &texture->dc_info[sub_resource_idx];
802 if (!dc_info->dc)
804 ERR("Sub-resource {%p, %u} has no DC.\n", texture, sub_resource_idx);
805 return;
808 TRACE("dc %p, bitmap %p.\n", dc_info->dc, dc_info->bitmap);
810 destroy_desc.hDc = dc_info->dc;
811 destroy_desc.hBitmap = dc_info->bitmap;
812 if ((status = D3DKMTDestroyDCFromMemory(&destroy_desc)))
813 ERR("Failed to destroy dc, status %#x.\n", status);
814 dc_info->dc = NULL;
815 dc_info->bitmap = NULL;
817 wined3d_texture_get_memory(texture, sub_resource_idx, &data, texture->resource.map_binding);
818 if (data.buffer_object)
820 context = context_acquire(device, NULL, 0);
821 wined3d_context_unmap_bo_address(context, &data, GL_PIXEL_UNPACK_BUFFER);
822 context_release(context);
826 void wined3d_texture_set_swapchain(struct wined3d_texture *texture, struct wined3d_swapchain *swapchain)
828 texture->swapchain = swapchain;
829 wined3d_resource_update_draw_binding(&texture->resource);
832 void wined3d_gl_texture_swizzle_from_color_fixup(GLint swizzle[4], struct color_fixup_desc fixup)
834 static const GLenum swizzle_source[] =
836 GL_ZERO, /* CHANNEL_SOURCE_ZERO */
837 GL_ONE, /* CHANNEL_SOURCE_ONE */
838 GL_RED, /* CHANNEL_SOURCE_X */
839 GL_GREEN, /* CHANNEL_SOURCE_Y */
840 GL_BLUE, /* CHANNEL_SOURCE_Z */
841 GL_ALPHA, /* CHANNEL_SOURCE_W */
844 swizzle[0] = swizzle_source[fixup.x_source];
845 swizzle[1] = swizzle_source[fixup.y_source];
846 swizzle[2] = swizzle_source[fixup.z_source];
847 swizzle[3] = swizzle_source[fixup.w_source];
850 /* Context activation is done by the caller. */
851 void wined3d_texture_gl_bind(struct wined3d_texture_gl *texture_gl,
852 struct wined3d_context_gl *context_gl, BOOL srgb)
854 const struct wined3d_format *format = texture_gl->t.resource.format;
855 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
856 const struct color_fixup_desc fixup = format->color_fixup;
857 struct gl_texture *gl_tex;
858 GLenum target;
860 TRACE("texture_gl %p, context_gl %p, srgb %#x.\n", texture_gl, context_gl, srgb);
862 if (!needs_separate_srgb_gl_texture(&context_gl->c, &texture_gl->t))
863 srgb = FALSE;
865 /* sRGB mode cache for preload() calls outside drawprim. */
866 if (srgb)
867 texture_gl->t.flags |= WINED3D_TEXTURE_IS_SRGB;
868 else
869 texture_gl->t.flags &= ~WINED3D_TEXTURE_IS_SRGB;
871 gl_tex = wined3d_texture_gl_get_gl_texture(texture_gl, srgb);
872 target = texture_gl->target;
874 if (gl_tex->name)
876 wined3d_context_gl_bind_texture(context_gl, target, gl_tex->name);
877 return;
880 gl_info->gl_ops.gl.p_glGenTextures(1, &gl_tex->name);
881 checkGLcall("glGenTextures");
882 TRACE("Generated texture %d.\n", gl_tex->name);
884 if (!gl_tex->name)
886 ERR("Failed to generate a texture name.\n");
887 return;
890 /* Initialise the state of the texture object to the OpenGL defaults, not
891 * the wined3d defaults. */
892 gl_tex->sampler_desc.address_u = WINED3D_TADDRESS_WRAP;
893 gl_tex->sampler_desc.address_v = WINED3D_TADDRESS_WRAP;
894 gl_tex->sampler_desc.address_w = WINED3D_TADDRESS_WRAP;
895 memset(gl_tex->sampler_desc.border_color, 0, sizeof(gl_tex->sampler_desc.border_color));
896 gl_tex->sampler_desc.mag_filter = WINED3D_TEXF_LINEAR;
897 gl_tex->sampler_desc.min_filter = WINED3D_TEXF_POINT; /* GL_NEAREST_MIPMAP_LINEAR */
898 gl_tex->sampler_desc.mip_filter = WINED3D_TEXF_LINEAR; /* GL_NEAREST_MIPMAP_LINEAR */
899 gl_tex->sampler_desc.lod_bias = 0.0f;
900 gl_tex->sampler_desc.min_lod = -1000.0f;
901 gl_tex->sampler_desc.max_lod = 1000.0f;
902 gl_tex->sampler_desc.max_anisotropy = 1;
903 gl_tex->sampler_desc.compare = FALSE;
904 gl_tex->sampler_desc.comparison_func = WINED3D_CMP_LESSEQUAL;
905 if (gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
906 gl_tex->sampler_desc.srgb_decode = TRUE;
907 else
908 gl_tex->sampler_desc.srgb_decode = srgb;
909 gl_tex->base_level = 0;
910 wined3d_texture_set_dirty(&texture_gl->t);
912 wined3d_context_gl_bind_texture(context_gl, target, gl_tex->name);
914 /* For a new texture we have to set the texture levels after binding the
915 * texture. Beware that texture rectangles do not support mipmapping, but
916 * set the maxmiplevel if we're relying on the partial
917 * GL_ARB_texture_non_power_of_two emulation with texture rectangles.
918 * (I.e., do not care about cond_np2 here, just look for
919 * GL_TEXTURE_RECTANGLE_ARB.) */
920 if (target != GL_TEXTURE_RECTANGLE_ARB)
922 TRACE("Setting GL_TEXTURE_MAX_LEVEL to %u.\n", texture_gl->t.level_count - 1);
923 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, texture_gl->t.level_count - 1);
924 checkGLcall("glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, texture->level_count)");
927 if (target == GL_TEXTURE_CUBE_MAP_ARB)
929 /* Cubemaps are always set to clamp, regardless of the sampler state. */
930 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
931 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
932 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
935 if (texture_gl->t.flags & WINED3D_TEXTURE_COND_NP2)
937 /* Conditinal non power of two textures use a different clamping
938 * default. If we're using the GL_WINE_normalized_texrect partial
939 * driver emulation, we're dealing with a GL_TEXTURE_2D texture which
940 * has the address mode set to repeat - something that prevents us
941 * from hitting the accelerated codepath. Thus manually set the GL
942 * state. The same applies to filtering. Even if the texture has only
943 * one mip level, the default LINEAR_MIPMAP_LINEAR filter causes a SW
944 * fallback on macos. */
945 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
946 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
947 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
948 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
949 checkGLcall("glTexParameteri");
950 gl_tex->sampler_desc.address_u = WINED3D_TADDRESS_CLAMP;
951 gl_tex->sampler_desc.address_v = WINED3D_TADDRESS_CLAMP;
952 gl_tex->sampler_desc.mag_filter = WINED3D_TEXF_POINT;
953 gl_tex->sampler_desc.min_filter = WINED3D_TEXF_POINT;
954 gl_tex->sampler_desc.mip_filter = WINED3D_TEXF_NONE;
957 if (gl_info->supported[WINED3D_GL_LEGACY_CONTEXT] && gl_info->supported[ARB_DEPTH_TEXTURE])
959 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY);
960 checkGLcall("glTexParameteri(GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY)");
963 if (!is_identity_fixup(fixup) && can_use_texture_swizzle(context_gl->c.d3d_info, format))
965 GLint swizzle[4];
967 wined3d_gl_texture_swizzle_from_color_fixup(swizzle, fixup);
968 gl_info->gl_ops.gl.p_glTexParameteriv(target, GL_TEXTURE_SWIZZLE_RGBA, swizzle);
969 checkGLcall("set format swizzle");
973 /* Context activation is done by the caller. */
974 void wined3d_texture_gl_bind_and_dirtify(struct wined3d_texture_gl *texture_gl,
975 struct wined3d_context_gl *context_gl, BOOL srgb)
977 /* We don't need a specific texture unit, but after binding the texture
978 * the current unit is dirty. Read the unit back instead of switching to
979 * 0, this avoids messing around with the state manager's GL states. The
980 * current texture unit should always be a valid one.
982 * To be more specific, this is tricky because we can implicitly be
983 * called from sampler() in state.c. This means we can't touch anything
984 * other than whatever happens to be the currently active texture, or we
985 * would risk marking already applied sampler states dirty again. */
986 if (context_gl->active_texture < ARRAY_SIZE(context_gl->rev_tex_unit_map))
988 unsigned int active_sampler = context_gl->rev_tex_unit_map[context_gl->active_texture];
989 if (active_sampler != WINED3D_UNMAPPED_STAGE)
990 context_invalidate_state(&context_gl->c, STATE_SAMPLER(active_sampler));
992 /* FIXME: Ideally we'd only do this when touching a binding that's used by
993 * a shader. */
994 context_invalidate_compute_state(&context_gl->c, STATE_COMPUTE_SHADER_RESOURCE_BINDING);
995 context_invalidate_state(&context_gl->c, STATE_GRAPHICS_SHADER_RESOURCE_BINDING);
997 wined3d_texture_gl_bind(texture_gl, context_gl, srgb);
1000 /* Context activation is done by the caller (state handler). */
1001 /* This function relies on the correct texture being bound and loaded. */
1002 void wined3d_texture_gl_apply_sampler_desc(struct wined3d_texture_gl *texture_gl,
1003 const struct wined3d_sampler_desc *sampler_desc, const struct wined3d_context_gl *context_gl)
1005 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
1006 GLenum target = texture_gl->target;
1007 struct gl_texture *gl_tex;
1008 DWORD state;
1010 TRACE("texture_gl %p, sampler_desc %p, context_gl %p.\n", texture_gl, sampler_desc, context_gl);
1012 gl_tex = wined3d_texture_gl_get_gl_texture(texture_gl, texture_gl->t.flags & WINED3D_TEXTURE_IS_SRGB);
1014 state = sampler_desc->address_u;
1015 if (state != gl_tex->sampler_desc.address_u)
1017 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_S,
1018 gl_info->wrap_lookup[state - WINED3D_TADDRESS_WRAP]);
1019 gl_tex->sampler_desc.address_u = state;
1022 state = sampler_desc->address_v;
1023 if (state != gl_tex->sampler_desc.address_v)
1025 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_T,
1026 gl_info->wrap_lookup[state - WINED3D_TADDRESS_WRAP]);
1027 gl_tex->sampler_desc.address_v = state;
1030 state = sampler_desc->address_w;
1031 if (state != gl_tex->sampler_desc.address_w)
1033 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_R,
1034 gl_info->wrap_lookup[state - WINED3D_TADDRESS_WRAP]);
1035 gl_tex->sampler_desc.address_w = state;
1038 if (memcmp(gl_tex->sampler_desc.border_color, sampler_desc->border_color,
1039 sizeof(gl_tex->sampler_desc.border_color)))
1041 gl_info->gl_ops.gl.p_glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, &sampler_desc->border_color[0]);
1042 memcpy(gl_tex->sampler_desc.border_color, sampler_desc->border_color,
1043 sizeof(gl_tex->sampler_desc.border_color));
1046 state = sampler_desc->mag_filter;
1047 if (state != gl_tex->sampler_desc.mag_filter)
1049 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MAG_FILTER, wined3d_gl_mag_filter(state));
1050 gl_tex->sampler_desc.mag_filter = state;
1053 if (sampler_desc->min_filter != gl_tex->sampler_desc.min_filter
1054 || sampler_desc->mip_filter != gl_tex->sampler_desc.mip_filter)
1056 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MIN_FILTER,
1057 wined3d_gl_min_mip_filter(sampler_desc->min_filter, sampler_desc->mip_filter));
1058 gl_tex->sampler_desc.min_filter = sampler_desc->min_filter;
1059 gl_tex->sampler_desc.mip_filter = sampler_desc->mip_filter;
1062 state = sampler_desc->max_anisotropy;
1063 if (state != gl_tex->sampler_desc.max_anisotropy)
1065 if (gl_info->supported[ARB_TEXTURE_FILTER_ANISOTROPIC])
1066 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MAX_ANISOTROPY, state);
1067 else
1068 WARN("Anisotropic filtering not supported.\n");
1069 gl_tex->sampler_desc.max_anisotropy = state;
1072 if (!sampler_desc->srgb_decode != !gl_tex->sampler_desc.srgb_decode
1073 && (context_gl->c.d3d_info->wined3d_creation_flags & WINED3D_SRGB_READ_WRITE_CONTROL)
1074 && gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
1076 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_SRGB_DECODE_EXT,
1077 sampler_desc->srgb_decode ? GL_DECODE_EXT : GL_SKIP_DECODE_EXT);
1078 gl_tex->sampler_desc.srgb_decode = sampler_desc->srgb_decode;
1081 if (!sampler_desc->compare != !gl_tex->sampler_desc.compare)
1083 if (sampler_desc->compare)
1084 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
1085 else
1086 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
1087 gl_tex->sampler_desc.compare = sampler_desc->compare;
1090 checkGLcall("Texture parameter application");
1092 if (gl_info->supported[EXT_TEXTURE_LOD_BIAS])
1094 gl_info->gl_ops.gl.p_glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT,
1095 GL_TEXTURE_LOD_BIAS_EXT, sampler_desc->lod_bias);
1096 checkGLcall("glTexEnvf(GL_TEXTURE_LOD_BIAS_EXT, ...)");
1100 ULONG CDECL wined3d_texture_incref(struct wined3d_texture *texture)
1102 ULONG refcount;
1104 TRACE("texture %p, swapchain %p.\n", texture, texture->swapchain);
1106 if (texture->swapchain)
1107 return wined3d_swapchain_incref(texture->swapchain);
1109 refcount = InterlockedIncrement(&texture->resource.ref);
1110 TRACE("%p increasing refcount to %u.\n", texture, refcount);
1112 return refcount;
1115 static void wined3d_texture_destroy_object(void *object)
1117 const struct wined3d_gl_info *gl_info = NULL;
1118 struct wined3d_texture *texture = object;
1119 struct wined3d_context *context = NULL;
1120 struct wined3d_dc_info *dc_info;
1121 unsigned int sub_count;
1122 GLuint buffer_object;
1123 unsigned int i;
1125 TRACE("texture %p.\n", texture);
1127 sub_count = texture->level_count * texture->layer_count;
1128 for (i = 0; i < sub_count; ++i)
1130 if (!(buffer_object = texture->sub_resources[i].buffer_object))
1131 continue;
1133 TRACE("Deleting buffer object %u.\n", buffer_object);
1135 /* We may not be able to get a context in
1136 * wined3d_texture_destroy_object() in general, but if a buffer object
1137 * was previously created we can. */
1138 if (!context)
1140 context = context_acquire(texture->resource.device, NULL, 0);
1141 gl_info = wined3d_context_gl(context)->gl_info;
1144 GL_EXTCALL(glDeleteBuffers(1, &buffer_object));
1147 if (context)
1148 context_release(context);
1150 if ((dc_info = texture->dc_info))
1152 for (i = 0; i < sub_count; ++i)
1154 if (dc_info[i].dc)
1156 struct wined3d_texture_idx texture_idx = {texture, i};
1158 wined3d_texture_destroy_dc(&texture_idx);
1161 heap_free(dc_info);
1164 if (texture->overlay_info)
1166 for (i = 0; i < sub_count; ++i)
1168 struct wined3d_overlay_info *info = &texture->overlay_info[i];
1169 struct wined3d_overlay_info *overlay, *cur;
1171 list_remove(&info->entry);
1172 LIST_FOR_EACH_ENTRY_SAFE(overlay, cur, &info->overlays, struct wined3d_overlay_info, entry)
1174 list_remove(&overlay->entry);
1177 heap_free(texture->overlay_info);
1181 void wined3d_texture_cleanup(struct wined3d_texture *texture)
1183 resource_cleanup(&texture->resource);
1184 wined3d_cs_destroy_object(texture->resource.device->cs, wined3d_texture_destroy_object, texture);
1187 static void wined3d_texture_cleanup_sync(struct wined3d_texture *texture)
1189 wined3d_texture_sub_resources_destroyed(texture);
1190 wined3d_texture_cleanup(texture);
1191 wined3d_resource_wait_idle(&texture->resource);
1194 ULONG CDECL wined3d_texture_decref(struct wined3d_texture *texture)
1196 ULONG refcount;
1198 TRACE("texture %p, swapchain %p.\n", texture, texture->swapchain);
1200 if (texture->swapchain)
1201 return wined3d_swapchain_decref(texture->swapchain);
1203 refcount = InterlockedDecrement(&texture->resource.ref);
1204 TRACE("%p decreasing refcount to %u.\n", texture, refcount);
1206 if (!refcount)
1208 /* Wait for the texture to become idle if it's using user memory,
1209 * since the application is allowed to free that memory once the
1210 * texture is destroyed. Note that this implies that
1211 * the destroy handler can't access that memory either. */
1212 if (texture->user_memory)
1213 wined3d_resource_wait_idle(&texture->resource);
1214 texture->resource.device->adapter->adapter_ops->adapter_destroy_texture(texture);
1217 return refcount;
1220 struct wined3d_resource * CDECL wined3d_texture_get_resource(struct wined3d_texture *texture)
1222 TRACE("texture %p.\n", texture);
1224 return &texture->resource;
1227 static BOOL color_key_equal(const struct wined3d_color_key *c1, struct wined3d_color_key *c2)
1229 return c1->color_space_low_value == c2->color_space_low_value
1230 && c1->color_space_high_value == c2->color_space_high_value;
1233 /* Context activation is done by the caller */
1234 void wined3d_texture_load(struct wined3d_texture *texture,
1235 struct wined3d_context *context, BOOL srgb)
1237 UINT sub_count = texture->level_count * texture->layer_count;
1238 const struct wined3d_d3d_info *d3d_info = context->d3d_info;
1239 DWORD flag;
1240 UINT i;
1242 TRACE("texture %p, context %p, srgb %#x.\n", texture, context, srgb);
1244 if (!needs_separate_srgb_gl_texture(context, texture))
1245 srgb = FALSE;
1247 if (srgb)
1248 flag = WINED3D_TEXTURE_SRGB_VALID;
1249 else
1250 flag = WINED3D_TEXTURE_RGB_VALID;
1252 if (!d3d_info->shader_color_key
1253 && (!(texture->async.flags & WINED3D_TEXTURE_ASYNC_COLOR_KEY)
1254 != !(texture->async.color_key_flags & WINED3D_CKEY_SRC_BLT)
1255 || (texture->async.flags & WINED3D_TEXTURE_ASYNC_COLOR_KEY
1256 && !color_key_equal(&texture->async.gl_color_key, &texture->async.src_blt_color_key))))
1258 unsigned int sub_count = texture->level_count * texture->layer_count;
1259 unsigned int i;
1261 TRACE("Reloading because of color key value change.\n");
1262 for (i = 0; i < sub_count; i++)
1264 if (!wined3d_texture_load_location(texture, i, context, texture->resource.map_binding))
1265 ERR("Failed to load location %s.\n", wined3d_debug_location(texture->resource.map_binding));
1266 else
1267 wined3d_texture_invalidate_location(texture, i, ~texture->resource.map_binding);
1270 texture->async.gl_color_key = texture->async.src_blt_color_key;
1273 if (texture->flags & flag)
1275 TRACE("Texture %p not dirty, nothing to do.\n", texture);
1276 return;
1279 /* Reload the surfaces if the texture is marked dirty. */
1280 for (i = 0; i < sub_count; ++i)
1282 if (!wined3d_texture_load_location(texture, i, context,
1283 srgb ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB))
1284 ERR("Failed to load location (srgb %#x).\n", srgb);
1286 texture->flags |= flag;
1289 void * CDECL wined3d_texture_get_parent(const struct wined3d_texture *texture)
1291 TRACE("texture %p.\n", texture);
1293 return texture->resource.parent;
1296 HRESULT wined3d_texture_check_box_dimensions(const struct wined3d_texture *texture,
1297 unsigned int level, const struct wined3d_box *box)
1299 const struct wined3d_format *format = texture->resource.format;
1300 unsigned int width_mask, height_mask, width, height, depth;
1302 width = wined3d_texture_get_level_width(texture, level);
1303 height = wined3d_texture_get_level_height(texture, level);
1304 depth = wined3d_texture_get_level_depth(texture, level);
1306 if (box->left >= box->right || box->right > width
1307 || box->top >= box->bottom || box->bottom > height
1308 || box->front >= box->back || box->back > depth)
1310 WARN("Box %s is invalid.\n", debug_box(box));
1311 return WINEDDERR_INVALIDRECT;
1314 if (texture->resource.format_flags & WINED3DFMT_FLAG_BLOCKS)
1316 /* This assumes power of two block sizes, but NPOT block sizes would
1317 * be silly anyway.
1319 * This also assumes that the format's block depth is 1. */
1320 width_mask = format->block_width - 1;
1321 height_mask = format->block_height - 1;
1323 if ((box->left & width_mask) || (box->top & height_mask)
1324 || (box->right & width_mask && box->right != width)
1325 || (box->bottom & height_mask && box->bottom != height))
1327 WARN("Box %s is misaligned for %ux%u blocks.\n",
1328 debug_box(box), format->block_width, format->block_height);
1329 return WINED3DERR_INVALIDCALL;
1333 return WINED3D_OK;
1336 void CDECL wined3d_texture_get_pitch(const struct wined3d_texture *texture,
1337 unsigned int level, unsigned int *row_pitch, unsigned int *slice_pitch)
1339 const struct wined3d_resource *resource = &texture->resource;
1340 unsigned int width = wined3d_texture_get_level_width(texture, level);
1341 unsigned int height = wined3d_texture_get_level_height(texture, level);
1343 if (texture->row_pitch)
1345 *row_pitch = texture->row_pitch;
1346 *slice_pitch = texture->slice_pitch;
1347 return;
1350 wined3d_format_calculate_pitch(resource->format, resource->device->surface_alignment,
1351 width, height, row_pitch, slice_pitch);
1354 DWORD CDECL wined3d_texture_set_lod(struct wined3d_texture *texture, DWORD lod)
1356 struct wined3d_resource *resource;
1357 DWORD old = texture->lod;
1359 TRACE("texture %p, lod %u.\n", texture, lod);
1361 /* The d3d9:texture test shows that SetLOD is ignored on non-managed
1362 * textures. The call always returns 0, and GetLOD always returns 0. */
1363 resource = &texture->resource;
1364 if (!wined3d_resource_access_is_managed(resource->access))
1366 TRACE("Ignoring LOD on texture with resource access %s.\n",
1367 wined3d_debug_resource_access(resource->access));
1368 return 0;
1371 if (lod >= texture->level_count)
1372 lod = texture->level_count - 1;
1374 if (texture->lod != lod)
1376 struct wined3d_device *device = resource->device;
1378 wined3d_resource_wait_idle(resource);
1379 texture->lod = lod;
1381 wined3d_texture_gl(texture)->texture_rgb.base_level = ~0u;
1382 wined3d_texture_gl(texture)->texture_srgb.base_level = ~0u;
1383 if (resource->bind_count)
1384 wined3d_cs_emit_set_sampler_state(device->cs, texture->sampler, WINED3D_SAMP_MAX_MIP_LEVEL,
1385 device->state.sampler_states[texture->sampler][WINED3D_SAMP_MAX_MIP_LEVEL]);
1388 return old;
1391 DWORD CDECL wined3d_texture_get_lod(const struct wined3d_texture *texture)
1393 TRACE("texture %p, returning %u.\n", texture, texture->lod);
1395 return texture->lod;
1398 DWORD CDECL wined3d_texture_get_level_count(const struct wined3d_texture *texture)
1400 TRACE("texture %p, returning %u.\n", texture, texture->level_count);
1402 return texture->level_count;
1405 HRESULT CDECL wined3d_texture_set_color_key(struct wined3d_texture *texture,
1406 DWORD flags, const struct wined3d_color_key *color_key)
1408 struct wined3d_device *device = texture->resource.device;
1409 static const DWORD all_flags = WINED3D_CKEY_DST_BLT | WINED3D_CKEY_DST_OVERLAY
1410 | WINED3D_CKEY_SRC_BLT | WINED3D_CKEY_SRC_OVERLAY;
1412 TRACE("texture %p, flags %#x, color_key %p.\n", texture, flags, color_key);
1414 if (flags & ~all_flags)
1416 WARN("Invalid flags passed, returning WINED3DERR_INVALIDCALL.\n");
1417 return WINED3DERR_INVALIDCALL;
1420 wined3d_cs_emit_set_color_key(device->cs, texture, flags, color_key);
1422 return WINED3D_OK;
1425 /* In D3D the depth stencil dimensions have to be greater than or equal to the
1426 * render target dimensions. With FBOs, the dimensions have to be an exact match. */
1427 /* TODO: We should synchronize the renderbuffer's content with the texture's content. */
1428 /* Context activation is done by the caller. */
1429 void wined3d_texture_gl_set_compatible_renderbuffer(struct wined3d_texture_gl *texture_gl,
1430 struct wined3d_context_gl *context_gl, unsigned int level, const struct wined3d_rendertarget_info *rt)
1432 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
1433 struct wined3d_renderbuffer_entry *entry;
1434 unsigned int src_width, src_height;
1435 unsigned int width, height;
1436 GLuint renderbuffer = 0;
1438 if (gl_info->supported[ARB_FRAMEBUFFER_OBJECT])
1439 return;
1441 if (rt && rt->resource->format->id != WINED3DFMT_NULL)
1443 struct wined3d_texture *rt_texture;
1444 unsigned int rt_level;
1446 if (rt->resource->type == WINED3D_RTYPE_BUFFER)
1448 FIXME("Unsupported resource type %s.\n", debug_d3dresourcetype(rt->resource->type));
1449 return;
1451 rt_texture = wined3d_texture_from_resource(rt->resource);
1452 rt_level = rt->sub_resource_idx % rt_texture->level_count;
1454 width = wined3d_texture_get_level_pow2_width(rt_texture, rt_level);
1455 height = wined3d_texture_get_level_pow2_height(rt_texture, rt_level);
1457 else
1459 width = wined3d_texture_get_level_pow2_width(&texture_gl->t, level);
1460 height = wined3d_texture_get_level_pow2_height(&texture_gl->t, level);
1463 src_width = wined3d_texture_get_level_pow2_width(&texture_gl->t, level);
1464 src_height = wined3d_texture_get_level_pow2_height(&texture_gl->t, level);
1466 /* A depth stencil smaller than the render target is not valid */
1467 if (width > src_width || height > src_height)
1468 return;
1470 /* Remove any renderbuffer set if the sizes match */
1471 if (width == src_width && height == src_height)
1473 texture_gl->current_renderbuffer = NULL;
1474 return;
1477 /* Look if we've already got a renderbuffer of the correct dimensions */
1478 LIST_FOR_EACH_ENTRY(entry, &texture_gl->renderbuffers, struct wined3d_renderbuffer_entry, entry)
1480 if (entry->width == width && entry->height == height)
1482 renderbuffer = entry->id;
1483 texture_gl->current_renderbuffer = entry;
1484 break;
1488 if (!renderbuffer)
1490 const struct wined3d_format_gl *format_gl;
1492 format_gl = wined3d_format_gl(texture_gl->t.resource.format);
1493 gl_info->fbo_ops.glGenRenderbuffers(1, &renderbuffer);
1494 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
1495 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER, format_gl->internal, width, height);
1497 entry = heap_alloc(sizeof(*entry));
1498 entry->width = width;
1499 entry->height = height;
1500 entry->id = renderbuffer;
1501 list_add_head(&texture_gl->renderbuffers, &entry->entry);
1503 texture_gl->current_renderbuffer = entry;
1506 checkGLcall("set compatible renderbuffer");
1509 HRESULT CDECL wined3d_texture_update_desc(struct wined3d_texture *texture, UINT width, UINT height,
1510 enum wined3d_format_id format_id, enum wined3d_multisample_type multisample_type,
1511 UINT multisample_quality, void *mem, UINT pitch)
1513 struct wined3d_texture_sub_resource *sub_resource;
1514 const struct wined3d_d3d_info *d3d_info;
1515 const struct wined3d_gl_info *gl_info;
1516 const struct wined3d_format *format;
1517 const struct wined3d *d3d;
1518 struct wined3d_device *device;
1519 unsigned int resource_size;
1520 DWORD valid_location = 0;
1521 BOOL create_dib = FALSE;
1523 TRACE("texture %p, width %u, height %u, format %s, multisample_type %#x, multisample_quality %u, "
1524 "mem %p, pitch %u.\n",
1525 texture, width, height, debug_d3dformat(format_id), multisample_type, multisample_quality, mem, pitch);
1527 device = texture->resource.device;
1528 d3d = device->wined3d;
1529 gl_info = &device->adapter->gl_info;
1530 d3d_info = &device->adapter->d3d_info;
1531 format = wined3d_get_format(device->adapter, format_id, texture->resource.bind_flags);
1532 resource_size = wined3d_format_calculate_size(format, device->surface_alignment, width, height, 1);
1534 if (!resource_size)
1535 return WINED3DERR_INVALIDCALL;
1537 if (texture->level_count * texture->layer_count > 1)
1539 WARN("Texture has multiple sub-resources, not supported.\n");
1540 return WINED3DERR_INVALIDCALL;
1543 if (texture->resource.type != WINED3D_RTYPE_TEXTURE_2D)
1545 WARN("Not supported on %s.\n", debug_d3dresourcetype(texture->resource.type));
1546 return WINED3DERR_INVALIDCALL;
1549 if (texture->resource.map_count)
1551 WARN("Texture is mapped.\n");
1552 return WINED3DERR_INVALIDCALL;
1555 /* We have no way of supporting a pitch that is not a multiple of the pixel
1556 * byte width short of uploading the texture row-by-row.
1557 * Fortunately that's not an issue since D3D9Ex doesn't allow a custom pitch
1558 * for user-memory textures (it always expects packed data) while DirectDraw
1559 * requires a 4-byte aligned pitch and doesn't support texture formats
1560 * larger than 4 bytes per pixel nor any format using 3 bytes per pixel.
1561 * This check is here to verify that the assumption holds. */
1562 if (pitch % texture->resource.format->byte_count)
1564 WARN("Pitch unsupported, not a multiple of the texture format byte width.\n");
1565 return WINED3DERR_INVALIDCALL;
1568 if (device->d3d_initialized)
1569 wined3d_cs_emit_unload_resource(device->cs, &texture->resource);
1570 wined3d_resource_wait_idle(&texture->resource);
1572 sub_resource = &texture->sub_resources[0];
1573 if (texture->dc_info && texture->dc_info[0].dc)
1575 struct wined3d_texture_idx texture_idx = {texture, 0};
1577 wined3d_cs_destroy_object(device->cs, wined3d_texture_destroy_dc, &texture_idx);
1578 wined3d_cs_finish(device->cs, WINED3D_CS_QUEUE_DEFAULT);
1579 create_dib = TRUE;
1582 wined3d_resource_free_sysmem(&texture->resource);
1584 if ((texture->row_pitch = pitch))
1585 texture->slice_pitch = height * pitch;
1586 else
1587 /* User memory surfaces don't have the regular surface alignment. */
1588 wined3d_format_calculate_pitch(format, 1, width, height,
1589 &texture->row_pitch, &texture->slice_pitch);
1591 texture->resource.format = format;
1592 texture->resource.multisample_type = multisample_type;
1593 texture->resource.multisample_quality = multisample_quality;
1594 texture->resource.width = width;
1595 texture->resource.height = height;
1596 if (!(texture->resource.access & WINED3D_RESOURCE_ACCESS_CPU) && d3d->flags & WINED3D_VIDMEM_ACCOUNTING)
1597 adapter_adjust_memory(device->adapter, (INT64)texture->slice_pitch - texture->resource.size);
1598 texture->resource.size = texture->slice_pitch;
1599 sub_resource->size = texture->slice_pitch;
1600 sub_resource->locations = WINED3D_LOCATION_DISCARDED;
1602 if (texture->texture_ops == &texture_gl_ops)
1604 if (multisample_type && gl_info->supported[ARB_TEXTURE_MULTISAMPLE])
1605 wined3d_texture_gl(texture)->target = GL_TEXTURE_2D_MULTISAMPLE;
1606 else
1607 wined3d_texture_gl(texture)->target = GL_TEXTURE_2D;
1610 if (((width & (width - 1)) || (height & (height - 1))) && !d3d_info->texture_npot
1611 && !d3d_info->texture_npot_conditional)
1613 texture->flags |= WINED3D_TEXTURE_COND_NP2_EMULATED;
1614 texture->pow2_width = texture->pow2_height = 1;
1615 while (texture->pow2_width < width)
1616 texture->pow2_width <<= 1;
1617 while (texture->pow2_height < height)
1618 texture->pow2_height <<= 1;
1620 else
1622 texture->flags &= ~WINED3D_TEXTURE_COND_NP2_EMULATED;
1623 texture->pow2_width = width;
1624 texture->pow2_height = height;
1627 if ((texture->user_memory = mem))
1629 texture->resource.map_binding = WINED3D_LOCATION_USER_MEMORY;
1630 valid_location = WINED3D_LOCATION_USER_MEMORY;
1632 else
1634 if (!wined3d_resource_prepare_sysmem(&texture->resource))
1635 ERR("Failed to allocate resource memory.\n");
1636 valid_location = WINED3D_LOCATION_SYSMEM;
1639 /* The format might be changed to a format that needs conversion.
1640 * If the surface didn't use PBOs previously but could now, don't
1641 * change it - whatever made us not use PBOs might come back, e.g.
1642 * color keys. */
1643 if (texture->resource.map_binding == WINED3D_LOCATION_BUFFER && !wined3d_texture_use_pbo(texture, gl_info))
1644 texture->resource.map_binding = WINED3D_LOCATION_SYSMEM;
1646 wined3d_texture_validate_location(texture, 0, valid_location);
1647 wined3d_texture_invalidate_location(texture, 0, ~valid_location);
1649 if (create_dib)
1651 struct wined3d_texture_idx texture_idx = {texture, 0};
1653 wined3d_cs_init_object(device->cs, wined3d_texture_create_dc, &texture_idx);
1654 wined3d_cs_finish(device->cs, WINED3D_CS_QUEUE_DEFAULT);
1657 return WINED3D_OK;
1660 /* Context activation is done by the caller. */
1661 static void wined3d_texture_prepare_buffer_object(struct wined3d_texture *texture,
1662 unsigned int sub_resource_idx, const struct wined3d_gl_info *gl_info)
1664 struct wined3d_texture_sub_resource *sub_resource;
1666 sub_resource = &texture->sub_resources[sub_resource_idx];
1667 if (sub_resource->buffer_object)
1668 return;
1670 GL_EXTCALL(glGenBuffers(1, &sub_resource->buffer_object));
1671 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, sub_resource->buffer_object));
1672 GL_EXTCALL(glBufferData(GL_PIXEL_UNPACK_BUFFER, sub_resource->size, NULL, GL_STREAM_DRAW));
1673 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));
1674 checkGLcall("Create buffer object");
1676 TRACE("Created buffer object %u for texture %p, sub-resource %u.\n",
1677 sub_resource->buffer_object, texture, sub_resource_idx);
1680 static void wined3d_texture_force_reload(struct wined3d_texture *texture)
1682 unsigned int sub_count = texture->level_count * texture->layer_count;
1683 unsigned int i;
1685 texture->flags &= ~(WINED3D_TEXTURE_RGB_ALLOCATED | WINED3D_TEXTURE_SRGB_ALLOCATED
1686 | WINED3D_TEXTURE_CONVERTED);
1687 texture->async.flags &= ~WINED3D_TEXTURE_ASYNC_COLOR_KEY;
1688 for (i = 0; i < sub_count; ++i)
1690 wined3d_texture_invalidate_location(texture, i,
1691 WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB);
1695 /* Context activation is done by the caller. */
1696 void wined3d_texture_gl_prepare_texture(struct wined3d_texture_gl *texture_gl,
1697 struct wined3d_context_gl *context_gl, BOOL srgb)
1699 DWORD alloc_flag = srgb ? WINED3D_TEXTURE_SRGB_ALLOCATED : WINED3D_TEXTURE_RGB_ALLOCATED;
1700 const struct wined3d_d3d_info *d3d_info = context_gl->c.d3d_info;
1701 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
1702 struct wined3d_resource *resource = &texture_gl->t.resource;
1703 const struct wined3d_device *device = resource->device;
1704 const struct wined3d_format *format = resource->format;
1705 const struct wined3d_color_key_conversion *conversion;
1706 const struct wined3d_format_gl *format_gl;
1707 GLenum internal;
1709 TRACE("texture_gl %p, context_gl %p, format %s.\n", texture_gl, context_gl, debug_d3dformat(format->id));
1711 if (!d3d_info->shader_color_key
1712 && !(texture_gl->t.async.flags & WINED3D_TEXTURE_ASYNC_COLOR_KEY)
1713 != !(texture_gl->t.async.color_key_flags & WINED3D_CKEY_SRC_BLT))
1715 wined3d_texture_force_reload(&texture_gl->t);
1717 if (texture_gl->t.async.color_key_flags & WINED3D_CKEY_SRC_BLT)
1718 texture_gl->t.async.flags |= WINED3D_TEXTURE_ASYNC_COLOR_KEY;
1721 if (texture_gl->t.flags & alloc_flag)
1722 return;
1724 if (resource->format_flags & WINED3DFMT_FLAG_DECOMPRESS)
1726 TRACE("WINED3DFMT_FLAG_DECOMPRESS set.\n");
1727 texture_gl->t.flags |= WINED3D_TEXTURE_CONVERTED;
1728 format = wined3d_resource_get_decompress_format(resource);
1730 else if (format->conv_byte_count)
1732 texture_gl->t.flags |= WINED3D_TEXTURE_CONVERTED;
1734 else if ((conversion = wined3d_format_get_color_key_conversion(&texture_gl->t, TRUE)))
1736 texture_gl->t.flags |= WINED3D_TEXTURE_CONVERTED;
1737 format = wined3d_get_format(device->adapter, conversion->dst_format, resource->bind_flags);
1738 TRACE("Using format %s for color key conversion.\n", debug_d3dformat(format->id));
1740 format_gl = wined3d_format_gl(format);
1742 wined3d_texture_gl_bind_and_dirtify(texture_gl, context_gl, srgb);
1744 if (srgb)
1745 internal = format_gl->srgb_internal;
1746 else if (resource->bind_flags & WINED3D_BIND_RENDER_TARGET && wined3d_resource_is_offscreen(resource))
1747 internal = format_gl->rt_internal;
1748 else
1749 internal = format_gl->internal;
1751 if (!internal)
1752 FIXME("No GL internal format for format %s.\n", debug_d3dformat(format->id));
1754 TRACE("internal %#x, format %#x, type %#x.\n", internal, format_gl->format, format_gl->type);
1756 if (wined3d_texture_use_immutable_storage(&texture_gl->t, gl_info))
1757 wined3d_texture_gl_allocate_immutable_storage(texture_gl, internal, gl_info);
1758 else
1759 wined3d_texture_gl_allocate_mutable_storage(texture_gl, internal, format_gl, gl_info);
1760 texture_gl->t.flags |= alloc_flag;
1763 static void wined3d_texture_gl_prepare_rb(struct wined3d_texture_gl *texture_gl,
1764 const struct wined3d_gl_info *gl_info, BOOL multisample)
1766 const struct wined3d_format_gl *format_gl;
1768 format_gl = wined3d_format_gl(texture_gl->t.resource.format);
1769 if (multisample)
1771 DWORD samples;
1773 if (texture_gl->rb_multisample)
1774 return;
1776 samples = wined3d_resource_get_sample_count(&texture_gl->t.resource);
1778 gl_info->fbo_ops.glGenRenderbuffers(1, &texture_gl->rb_multisample);
1779 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, texture_gl->rb_multisample);
1780 gl_info->fbo_ops.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,
1781 format_gl->internal, texture_gl->t.resource.width, texture_gl->t.resource.height);
1782 checkGLcall("glRenderbufferStorageMultisample()");
1783 TRACE("Created multisample rb %u.\n", texture_gl->rb_multisample);
1785 else
1787 if (texture_gl->rb_resolved)
1788 return;
1790 gl_info->fbo_ops.glGenRenderbuffers(1, &texture_gl->rb_resolved);
1791 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, texture_gl->rb_resolved);
1792 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER, format_gl->internal,
1793 texture_gl->t.resource.width, texture_gl->t.resource.height);
1794 checkGLcall("glRenderbufferStorage()");
1795 TRACE("Created resolved rb %u.\n", texture_gl->rb_resolved);
1799 BOOL wined3d_texture_prepare_location(struct wined3d_texture *texture,
1800 unsigned int sub_resource_idx, struct wined3d_context *context, unsigned int location)
1802 return texture->texture_ops->texture_prepare_location(texture, sub_resource_idx, context, location);
1805 static struct wined3d_texture_sub_resource *wined3d_texture_get_sub_resource(struct wined3d_texture *texture,
1806 unsigned int sub_resource_idx)
1808 UINT sub_count = texture->level_count * texture->layer_count;
1810 TRACE("texture %p, sub_resource_idx %u.\n", texture, sub_resource_idx);
1812 if (sub_resource_idx >= sub_count)
1814 WARN("sub_resource_idx %u >= sub_count %u.\n", sub_resource_idx, sub_count);
1815 return NULL;
1818 return &texture->sub_resources[sub_resource_idx];
1821 HRESULT CDECL wined3d_texture_add_dirty_region(struct wined3d_texture *texture,
1822 UINT layer, const struct wined3d_box *dirty_region)
1824 TRACE("texture %p, layer %u, dirty_region %s.\n", texture, layer, debug_box(dirty_region));
1826 if (layer >= texture->layer_count)
1828 WARN("Invalid layer %u specified.\n", layer);
1829 return WINED3DERR_INVALIDCALL;
1832 if (dirty_region)
1833 FIXME("Ignoring dirty_region %s.\n", debug_box(dirty_region));
1835 wined3d_cs_emit_add_dirty_texture_region(texture->resource.device->cs, texture, layer);
1837 return WINED3D_OK;
1840 static void wined3d_texture_gl_upload_data(struct wined3d_context *context,
1841 const struct wined3d_const_bo_address *src_bo_addr, const struct wined3d_format *src_format,
1842 const struct wined3d_box *src_box, unsigned int src_row_pitch, unsigned int src_slice_pitch,
1843 struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, unsigned int dst_location,
1844 unsigned int dst_x, unsigned int dst_y, unsigned int dst_z)
1846 struct wined3d_context_gl *context_gl = wined3d_context_gl(context);
1847 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
1848 unsigned int update_w = src_box->right - src_box->left;
1849 unsigned int update_h = src_box->bottom - src_box->top;
1850 unsigned int update_d = src_box->back - src_box->front;
1851 const struct wined3d_format_gl *format_gl;
1852 struct wined3d_bo_address bo;
1853 void *converted_mem = NULL;
1854 struct wined3d_format_gl f;
1855 unsigned int level;
1856 BOOL decompress;
1857 GLenum target;
1859 BOOL srgb = FALSE;
1861 TRACE("context %p, src_bo_addr %s, src_format %s, src_box %s, src_row_pitch %u, src_slice_pitch %u, "
1862 "dst_texture %p, dst_sub_resource_idx %u, dst_location %s, dst_x %u, dst_y %u, dst_z %u.\n",
1863 context, debug_const_bo_address(src_bo_addr), debug_d3dformat(src_format->id), debug_box(src_box),
1864 src_row_pitch, src_slice_pitch, dst_texture, dst_sub_resource_idx,
1865 wined3d_debug_location(dst_location), dst_x, dst_y, dst_z);
1867 if (dst_location == WINED3D_LOCATION_TEXTURE_SRGB)
1869 srgb = TRUE;
1871 else if (dst_location != WINED3D_LOCATION_TEXTURE_RGB)
1873 FIXME("Unhandled location %s.\n", wined3d_debug_location(dst_location));
1874 return;
1877 wined3d_texture_gl_bind_and_dirtify(wined3d_texture_gl(dst_texture), wined3d_context_gl(context), srgb);
1879 if (dst_texture->sub_resources[dst_sub_resource_idx].map_count)
1881 WARN("Uploading a texture that is currently mapped, setting WINED3D_TEXTURE_PIN_SYSMEM.\n");
1882 dst_texture->flags |= WINED3D_TEXTURE_PIN_SYSMEM;
1885 if (src_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_HEIGHT_SCALE)
1887 update_h *= src_format->height_scale.numerator;
1888 update_h /= src_format->height_scale.denominator;
1891 target = wined3d_texture_gl_get_sub_resource_target(wined3d_texture_gl(dst_texture), dst_sub_resource_idx);
1892 level = dst_sub_resource_idx % dst_texture->level_count;
1894 switch (target)
1896 case GL_TEXTURE_1D_ARRAY:
1897 dst_y = dst_sub_resource_idx / dst_texture->level_count;
1898 update_h = 1;
1899 break;
1900 case GL_TEXTURE_2D_ARRAY:
1901 dst_z = dst_sub_resource_idx / dst_texture->level_count;
1902 update_d = 1;
1903 break;
1904 case GL_TEXTURE_2D_MULTISAMPLE:
1905 case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
1906 FIXME("Not supported for multisample textures.\n");
1907 return;
1910 bo.buffer_object = src_bo_addr->buffer_object;
1911 bo.addr = (BYTE *)src_bo_addr->addr + src_box->front * src_slice_pitch;
1912 if (dst_texture->resource.format_flags & WINED3DFMT_FLAG_BLOCKS)
1914 bo.addr += (src_box->top / src_format->block_height) * src_row_pitch;
1915 bo.addr += (src_box->left / src_format->block_width) * src_format->block_byte_count;
1917 else
1919 bo.addr += src_box->top * src_row_pitch;
1920 bo.addr += src_box->left * src_format->byte_count;
1923 decompress = dst_texture->resource.format_flags & WINED3DFMT_FLAG_DECOMPRESS;
1924 if (src_format->upload || decompress)
1926 const struct wined3d_format *compressed_format = src_format;
1927 unsigned int dst_row_pitch, dst_slice_pitch;
1928 void *src_mem;
1930 if (decompress)
1932 src_format = wined3d_resource_get_decompress_format(&dst_texture->resource);
1934 else
1936 if (dst_texture->resource.format_flags & WINED3DFMT_FLAG_BLOCKS)
1937 ERR("Converting a block-based format.\n");
1939 f = *wined3d_format_gl(src_format);
1940 f.f.byte_count = src_format->conv_byte_count;
1941 src_format = &f.f;
1944 wined3d_format_calculate_pitch(src_format, 1, update_w, update_h, &dst_row_pitch, &dst_slice_pitch);
1946 /* Note that uploading 3D textures may require quite some address
1947 * space; it may make sense to upload them per-slice instead. */
1948 if (!(converted_mem = heap_calloc(update_d, dst_slice_pitch)))
1950 ERR("Failed to allocate upload buffer.\n");
1951 return;
1954 src_mem = wined3d_context_gl_map_bo_address(context_gl, &bo,
1955 src_slice_pitch, GL_PIXEL_UNPACK_BUFFER, WINED3D_MAP_READ);
1956 if (decompress)
1957 compressed_format->decompress(src_mem, converted_mem, src_row_pitch, src_slice_pitch,
1958 dst_row_pitch, dst_slice_pitch, update_w, update_h, update_d);
1959 else
1960 src_format->upload(src_mem, converted_mem, src_row_pitch, src_slice_pitch,
1961 dst_row_pitch, dst_slice_pitch, update_w, update_h, update_d);
1962 wined3d_context_gl_unmap_bo_address(context_gl, &bo, GL_PIXEL_UNPACK_BUFFER);
1964 bo.buffer_object = 0;
1965 bo.addr = converted_mem;
1966 src_row_pitch = dst_row_pitch;
1967 src_slice_pitch = dst_slice_pitch;
1970 if (bo.buffer_object)
1972 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, bo.buffer_object));
1973 checkGLcall("glBindBuffer");
1976 format_gl = wined3d_format_gl(src_format);
1977 if (src_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_COMPRESSED)
1979 unsigned int dst_row_pitch, dst_slice_pitch;
1980 const BYTE *addr = bo.addr;
1981 GLenum internal;
1983 if (srgb)
1984 internal = format_gl->srgb_internal;
1985 else if (dst_texture->resource.bind_flags & WINED3D_BIND_RENDER_TARGET
1986 && wined3d_resource_is_offscreen(&dst_texture->resource))
1987 internal = format_gl->rt_internal;
1988 else
1989 internal = format_gl->internal;
1991 wined3d_format_calculate_pitch(src_format, 1, update_w, update_h, &dst_row_pitch, &dst_slice_pitch);
1993 TRACE("Uploading compressed data, target %#x, level %u, x %u, y %u, z %u, "
1994 "w %u, h %u, d %u, format %#x, image_size %#x, addr %p.\n",
1995 target, level, dst_x, dst_y, dst_z, update_w, update_h,
1996 update_d, internal, dst_slice_pitch, addr);
1998 if (target == GL_TEXTURE_1D)
2000 GL_EXTCALL(glCompressedTexSubImage1D(target, level, dst_x,
2001 update_w, internal, dst_row_pitch, addr));
2003 else if (dst_row_pitch == src_row_pitch)
2005 if (target == GL_TEXTURE_2D_ARRAY || target == GL_TEXTURE_3D)
2007 GL_EXTCALL(glCompressedTexSubImage3D(target, level, dst_x, dst_y, dst_z,
2008 update_w, update_h, update_d, internal, dst_slice_pitch * update_d, addr));
2010 else
2012 GL_EXTCALL(glCompressedTexSubImage2D(target, level, dst_x, dst_y,
2013 update_w, update_h, internal, dst_slice_pitch, addr));
2016 else
2018 unsigned int row_count = (update_h + src_format->block_height - 1) / src_format->block_height;
2019 unsigned int row, y, z;
2021 /* glCompressedTexSubImage2D() ignores pixel store state, so we
2022 * can't use the unpack row length like for glTexSubImage2D. */
2023 for (z = dst_z; z < dst_z + update_d; ++z)
2025 for (row = 0, y = dst_y; row < row_count; ++row)
2027 if (target == GL_TEXTURE_2D_ARRAY || target == GL_TEXTURE_3D)
2029 GL_EXTCALL(glCompressedTexSubImage3D(target, level, dst_x, y, z,
2030 update_w, src_format->block_height, 1, internal, dst_row_pitch, addr));
2032 else
2034 GL_EXTCALL(glCompressedTexSubImage2D(target, level, dst_x, y,
2035 update_w, src_format->block_height, internal, dst_row_pitch, addr));
2038 y += src_format->block_height;
2039 addr += src_row_pitch;
2043 checkGLcall("Upload compressed texture data");
2045 else
2047 TRACE("Uploading data, target %#x, level %u, x %u, y %u, z %u, "
2048 "w %u, h %u, d %u, format %#x, type %#x, addr %p.\n",
2049 target, level, dst_x, dst_y, dst_z, update_w, update_h,
2050 update_d, format_gl->format, format_gl->type, bo.addr);
2052 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, src_row_pitch / src_format->byte_count);
2053 if (target == GL_TEXTURE_2D_ARRAY || target == GL_TEXTURE_3D)
2055 GL_EXTCALL(glTexSubImage3D(target, level, dst_x, dst_y, dst_z,
2056 update_w, update_h, update_d, format_gl->format, format_gl->type, bo.addr));
2058 else if (target == GL_TEXTURE_1D)
2060 gl_info->gl_ops.gl.p_glTexSubImage1D(target, level, dst_x,
2061 update_w, format_gl->format, format_gl->type, bo.addr);
2063 else
2065 gl_info->gl_ops.gl.p_glTexSubImage2D(target, level, dst_x, dst_y,
2066 update_w, update_h, format_gl->format, format_gl->type, bo.addr);
2068 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
2069 checkGLcall("Upload texture data");
2072 if (bo.buffer_object)
2074 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));
2075 checkGLcall("glBindBuffer");
2077 heap_free(converted_mem);
2079 if (gl_info->quirks & WINED3D_QUIRK_FBO_TEX_UPDATE)
2081 struct wined3d_device *device = dst_texture->resource.device;
2082 unsigned int i;
2084 for (i = 0; i < device->context_count; ++i)
2086 wined3d_context_gl_texture_update(wined3d_context_gl(device->contexts[i]), wined3d_texture_gl(dst_texture));
2091 static void wined3d_texture_gl_download_data_slow_path(struct wined3d_texture_gl *texture_gl,
2092 unsigned int sub_resource_idx, struct wined3d_context_gl *context_gl, const struct wined3d_bo_address *data)
2094 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
2095 struct wined3d_texture_sub_resource *sub_resource;
2096 unsigned int dst_row_pitch, dst_slice_pitch;
2097 unsigned int src_row_pitch, src_slice_pitch;
2098 const struct wined3d_format_gl *format_gl;
2099 BYTE *temporary_mem = NULL;
2100 unsigned int level;
2101 GLenum target;
2102 void *mem;
2104 format_gl = wined3d_format_gl(texture_gl->t.resource.format);
2106 /* Only support read back of converted P8 textures. */
2107 if (texture_gl->t.flags & WINED3D_TEXTURE_CONVERTED && format_gl->f.id != WINED3DFMT_P8_UINT
2108 && !format_gl->f.download)
2110 ERR("Trying to read back converted texture %p, %u with format %s.\n",
2111 texture_gl, sub_resource_idx, debug_d3dformat(format_gl->f.id));
2112 return;
2115 sub_resource = &texture_gl->t.sub_resources[sub_resource_idx];
2116 target = wined3d_texture_gl_get_sub_resource_target(texture_gl, sub_resource_idx);
2117 level = sub_resource_idx % texture_gl->t.level_count;
2119 if (target == GL_TEXTURE_1D_ARRAY || target == GL_TEXTURE_2D_ARRAY)
2121 if (format_gl->f.download)
2123 FIXME("Reading back converted array texture %p is not supported.\n", texture_gl);
2124 return;
2127 /* NP2 emulation is not allowed on array textures. */
2128 if (texture_gl->t.flags & WINED3D_TEXTURE_COND_NP2_EMULATED)
2129 ERR("Array texture %p uses NP2 emulation.\n", texture_gl);
2131 WARN_(d3d_perf)("Downloading all miplevel layers to get the data for a single sub-resource.\n");
2133 if (!(temporary_mem = heap_calloc(texture_gl->t.layer_count, sub_resource->size)))
2135 ERR("Out of memory.\n");
2136 return;
2140 if (texture_gl->t.flags & WINED3D_TEXTURE_COND_NP2_EMULATED)
2142 if (format_gl->f.download)
2144 FIXME("Reading back converted texture %p with NP2 emulation is not supported.\n", texture_gl);
2145 return;
2148 wined3d_texture_get_pitch(&texture_gl->t, level, &dst_row_pitch, &dst_slice_pitch);
2149 wined3d_format_calculate_pitch(&format_gl->f, texture_gl->t.resource.device->surface_alignment,
2150 wined3d_texture_get_level_pow2_width(&texture_gl->t, level),
2151 wined3d_texture_get_level_pow2_height(&texture_gl->t, level),
2152 &src_row_pitch, &src_slice_pitch);
2153 if (!(temporary_mem = heap_alloc(src_slice_pitch)))
2155 ERR("Out of memory.\n");
2156 return;
2159 if (data->buffer_object)
2160 ERR("NP2 emulated texture uses PBO unexpectedly.\n");
2161 if (texture_gl->t.resource.format_flags & WINED3DFMT_FLAG_COMPRESSED)
2162 ERR("Unexpected compressed format for NP2 emulated texture.\n");
2165 if (format_gl->f.download)
2167 struct wined3d_format f;
2169 if (data->buffer_object)
2170 ERR("Converted texture %p uses PBO unexpectedly.\n", texture_gl);
2172 WARN_(d3d_perf)("Downloading converted texture %p, %u with format %s.\n",
2173 texture_gl, sub_resource_idx, debug_d3dformat(format_gl->f.id));
2175 f = format_gl->f;
2176 f.byte_count = format_gl->f.conv_byte_count;
2177 wined3d_texture_get_pitch(&texture_gl->t, level, &dst_row_pitch, &dst_slice_pitch);
2178 wined3d_format_calculate_pitch(&f, texture_gl->t.resource.device->surface_alignment,
2179 wined3d_texture_get_level_width(&texture_gl->t, level),
2180 wined3d_texture_get_level_height(&texture_gl->t, level),
2181 &src_row_pitch, &src_slice_pitch);
2183 if (!(temporary_mem = heap_alloc(src_slice_pitch)))
2185 ERR("Failed to allocate memory.\n");
2186 return;
2190 if (temporary_mem)
2192 mem = temporary_mem;
2194 else if (data->buffer_object)
2196 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, data->buffer_object));
2197 checkGLcall("glBindBuffer");
2198 mem = data->addr;
2200 else
2202 mem = data->addr;
2205 if (texture_gl->t.resource.format_flags & WINED3DFMT_FLAG_COMPRESSED)
2207 TRACE("Downloading compressed texture %p, %u, level %u, format %#x, type %#x, data %p.\n",
2208 texture_gl, sub_resource_idx, level, format_gl->format, format_gl->type, mem);
2210 GL_EXTCALL(glGetCompressedTexImage(target, level, mem));
2211 checkGLcall("glGetCompressedTexImage");
2213 else
2215 TRACE("Downloading texture %p, %u, level %u, format %#x, type %#x, data %p.\n",
2216 texture_gl, sub_resource_idx, level, format_gl->format, format_gl->type, mem);
2218 gl_info->gl_ops.gl.p_glGetTexImage(target, level, format_gl->format, format_gl->type, mem);
2219 checkGLcall("glGetTexImage");
2222 if (format_gl->f.download)
2224 format_gl->f.download(mem, data->addr, src_row_pitch, src_slice_pitch, dst_row_pitch, dst_slice_pitch,
2225 wined3d_texture_get_level_width(&texture_gl->t, level),
2226 wined3d_texture_get_level_height(&texture_gl->t, level), 1);
2228 else if (texture_gl->t.flags & WINED3D_TEXTURE_COND_NP2_EMULATED)
2230 const BYTE *src_data;
2231 unsigned int h, y;
2232 BYTE *dst_data;
2233 /* Some games (e.g. Warhammer 40,000) don't properly handle texture
2234 * pitches, preventing us from using the texture pitch to box NPOT
2235 * textures. Instead, we repack the texture's CPU copy so that its
2236 * pitch equals bpp * width instead of bpp * pow2width.
2238 * Instead of boxing the texture:
2240 * │<── texture width ──>│ pow2 width ──>│
2241 * ├─────────────────────┼───────────────┼─
2242 * │111111111111111111111│ │ʌ
2243 * │222222222222222222222│ ││
2244 * │333333333333333333333│ padding │texture height
2245 * │444444444444444444444│ ││
2246 * │555555555555555555555│ │v
2247 * ├─────────────────────┘ ├─
2248 * │ │pow2 height
2249 * │ padding padding ││
2250 * │ │v
2251 * └─────────────────────────────────────┴─
2253 * we're repacking the data to the expected texture width
2255 * │<── texture width ──>│ pow2 width ──>│
2256 * ├─────────────────────┴───────────────┼─
2257 * │1111111111111111111112222222222222222│ʌ
2258 * │2222233333333333333333333344444444444││
2259 * │4444444444555555555555555555555 │texture height
2260 * │ ││
2261 * │ padding padding │v
2262 * │ ├─
2263 * │ │pow2 height
2264 * │ padding padding ││
2265 * │ │v
2266 * └─────────────────────────────────────┴─
2268 * == is the same as
2270 * │<── texture width ──>│
2271 * ├─────────────────────┼─
2272 * │111111111111111111111│ʌ
2273 * │222222222222222222222││
2274 * │333333333333333333333│texture height
2275 * │444444444444444444444││
2276 * │555555555555555555555│v
2277 * └─────────────────────┴─
2279 * This also means that any references to surface memory should work
2280 * with the data as if it were a standard texture with a NPOT width
2281 * instead of a texture boxed up to be a power-of-two texture. */
2282 src_data = mem;
2283 dst_data = data->addr;
2284 TRACE("Repacking the surface data from pitch %u to pitch %u.\n", src_row_pitch, dst_row_pitch);
2285 h = wined3d_texture_get_level_height(&texture_gl->t, level);
2286 for (y = 0; y < h; ++y)
2288 memcpy(dst_data, src_data, dst_row_pitch);
2289 src_data += src_row_pitch;
2290 dst_data += dst_row_pitch;
2293 else if (temporary_mem)
2295 unsigned int layer = sub_resource_idx / texture_gl->t.level_count;
2296 void *src_data = temporary_mem + layer * sub_resource->size;
2297 if (data->buffer_object)
2299 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, data->buffer_object));
2300 checkGLcall("glBindBuffer");
2301 GL_EXTCALL(glBufferSubData(GL_PIXEL_PACK_BUFFER, 0, sub_resource->size, src_data));
2302 checkGLcall("glBufferSubData");
2304 else
2306 memcpy(data->addr, src_data, sub_resource->size);
2310 if (data->buffer_object)
2312 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
2313 checkGLcall("glBindBuffer");
2316 heap_free(temporary_mem);
2319 static void wined3d_texture_gl_download_data(struct wined3d_context *context,
2320 struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx, unsigned int src_location,
2321 const struct wined3d_box *src_box, const struct wined3d_bo_address *dst_bo_addr,
2322 const struct wined3d_format *dst_format, unsigned int dst_x, unsigned int dst_y, unsigned int dst_z,
2323 unsigned int dst_row_pitch, unsigned int dst_slice_pitch)
2325 struct wined3d_texture_gl *src_texture_gl = wined3d_texture_gl(src_texture);
2326 struct wined3d_context_gl *context_gl = wined3d_context_gl(context);
2327 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
2328 unsigned int src_level, src_width, src_height, src_depth;
2329 unsigned int src_row_pitch, src_slice_pitch;
2330 const struct wined3d_format_gl *format_gl;
2331 BOOL srgb = FALSE;
2332 GLenum target;
2334 TRACE("context %p, src_texture %p, src_sub_resource_idx %u, src_location %s, src_box %s, dst_bo_addr %s, "
2335 "dst_format %s, dst_x %u, dst_y %u, dst_z %u, dst_row_pitch %u, dst_slice_pitch %u.\n",
2336 context, src_texture, src_sub_resource_idx, wined3d_debug_location(src_location),
2337 debug_box(src_box), debug_bo_address(dst_bo_addr), debug_d3dformat(dst_format->id),
2338 dst_x, dst_y, dst_z, dst_row_pitch, dst_slice_pitch);
2340 if (src_location == WINED3D_LOCATION_TEXTURE_SRGB)
2342 srgb = TRUE;
2344 else if (src_location != WINED3D_LOCATION_TEXTURE_RGB)
2346 FIXME("Unhandled location %s.\n", wined3d_debug_location(src_location));
2347 return;
2350 src_level = src_sub_resource_idx % src_texture->level_count;
2351 src_width = wined3d_texture_get_level_width(src_texture, src_level);
2352 src_height = wined3d_texture_get_level_height(src_texture, src_level);
2353 src_depth = wined3d_texture_get_level_depth(src_texture, src_level);
2354 if (src_box->left || src_box->top || src_box->right != src_width || src_box->bottom != src_height
2355 || src_box->front || src_box->back != src_depth)
2357 FIXME("Unhandled source box %s.\n", debug_box(src_box));
2358 return;
2361 if (dst_x || dst_y || dst_z)
2363 FIXME("Unhandled destination (%u, %u, %u).\n", dst_x, dst_y, dst_z);
2364 return;
2367 if (dst_format->id != src_texture->resource.format->id)
2369 FIXME("Unhandled format conversion (%s -> %s).\n",
2370 debug_d3dformat(src_texture->resource.format->id),
2371 debug_d3dformat(dst_format->id));
2372 return;
2375 wined3d_texture_get_pitch(src_texture, src_level, &src_row_pitch, &src_slice_pitch);
2376 if (src_row_pitch != dst_row_pitch || src_slice_pitch != dst_slice_pitch)
2378 FIXME("Unhandled destination pitches %u/%u (source pitches %u/%u).\n",
2379 dst_row_pitch, dst_slice_pitch, src_row_pitch, src_slice_pitch);
2380 return;
2383 wined3d_texture_gl_bind_and_dirtify(src_texture_gl, context_gl, srgb);
2385 format_gl = wined3d_format_gl(src_texture->resource.format);
2386 target = wined3d_texture_gl_get_sub_resource_target(src_texture_gl, src_sub_resource_idx);
2388 if ((src_texture->resource.type == WINED3D_RTYPE_TEXTURE_2D
2389 && (target == GL_TEXTURE_2D_ARRAY || format_gl->f.conv_byte_count
2390 || src_texture->flags & (WINED3D_TEXTURE_CONVERTED | WINED3D_TEXTURE_COND_NP2_EMULATED)))
2391 || target == GL_TEXTURE_1D_ARRAY)
2393 wined3d_texture_gl_download_data_slow_path(src_texture_gl, src_sub_resource_idx, context_gl, dst_bo_addr);
2394 return;
2397 if (format_gl->f.conv_byte_count)
2399 FIXME("Attempting to download a converted texture, type %s format %s.\n",
2400 debug_d3dresourcetype(src_texture->resource.type),
2401 debug_d3dformat(format_gl->f.id));
2402 return;
2405 if (dst_bo_addr->buffer_object)
2407 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, dst_bo_addr->buffer_object));
2408 checkGLcall("glBindBuffer");
2411 if (src_texture->resource.format_flags & WINED3DFMT_FLAG_COMPRESSED)
2413 TRACE("Downloading compressed texture %p, %u, level %u, format %#x, type %#x, data %p.\n",
2414 src_texture, src_sub_resource_idx, src_level, format_gl->format, format_gl->type, dst_bo_addr->addr);
2416 GL_EXTCALL(glGetCompressedTexImage(target, src_level, dst_bo_addr->addr));
2417 checkGLcall("glGetCompressedTexImage");
2419 else
2421 TRACE("Downloading texture %p, %u, level %u, format %#x, type %#x, data %p.\n",
2422 src_texture, src_sub_resource_idx, src_level, format_gl->format, format_gl->type, dst_bo_addr->addr);
2424 gl_info->gl_ops.gl.p_glGetTexImage(target, src_level, format_gl->format, format_gl->type, dst_bo_addr->addr);
2425 checkGLcall("glGetTexImage");
2428 if (dst_bo_addr->buffer_object)
2430 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
2431 checkGLcall("glBindBuffer");
2435 /* Context activation is done by the caller. */
2436 static BOOL wined3d_texture_gl_load_sysmem(struct wined3d_texture_gl *texture_gl,
2437 unsigned int sub_resource_idx, struct wined3d_context_gl *context_gl, DWORD dst_location)
2439 struct wined3d_texture_sub_resource *sub_resource;
2441 sub_resource = &texture_gl->t.sub_resources[sub_resource_idx];
2443 /* We cannot download data from multisample textures directly. */
2444 if (wined3d_texture_gl_is_multisample_location(texture_gl, WINED3D_LOCATION_TEXTURE_RGB))
2446 wined3d_texture_load_location(&texture_gl->t, sub_resource_idx, &context_gl->c, WINED3D_LOCATION_RB_RESOLVED);
2447 texture2d_read_from_framebuffer(&texture_gl->t, sub_resource_idx, &context_gl->c,
2448 WINED3D_LOCATION_RB_RESOLVED, dst_location);
2449 return TRUE;
2452 if (sub_resource->locations & (WINED3D_LOCATION_RB_MULTISAMPLE | WINED3D_LOCATION_RB_RESOLVED))
2453 wined3d_texture_load_location(&texture_gl->t, sub_resource_idx, &context_gl->c, WINED3D_LOCATION_TEXTURE_RGB);
2455 /* Download the sub-resource to system memory. */
2456 if (sub_resource->locations & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB))
2458 unsigned int row_pitch, slice_pitch, level;
2459 struct wined3d_bo_address data;
2460 struct wined3d_box src_box;
2461 unsigned int src_location;
2463 level = sub_resource_idx % texture_gl->t.level_count;
2464 wined3d_texture_get_memory(&texture_gl->t, sub_resource_idx, &data, dst_location);
2465 src_location = sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB
2466 ? WINED3D_LOCATION_TEXTURE_RGB : WINED3D_LOCATION_TEXTURE_SRGB;
2467 wined3d_texture_get_level_box(&texture_gl->t, level, &src_box);
2468 wined3d_texture_get_pitch(&texture_gl->t, level, &row_pitch, &slice_pitch);
2469 wined3d_texture_gl_download_data(&context_gl->c, &texture_gl->t, sub_resource_idx, src_location,
2470 &src_box, &data, texture_gl->t.resource.format, 0, 0, 0, row_pitch, slice_pitch);
2472 ++texture_gl->t.download_count;
2473 return TRUE;
2476 if (!(texture_gl->t.resource.bind_flags & WINED3D_BIND_DEPTH_STENCIL)
2477 && (sub_resource->locations & WINED3D_LOCATION_DRAWABLE))
2479 texture2d_read_from_framebuffer(&texture_gl->t, sub_resource_idx, &context_gl->c,
2480 texture_gl->t.resource.draw_binding, dst_location);
2481 return TRUE;
2484 FIXME("Can't load texture %p, %u with location flags %s into sysmem.\n",
2485 texture_gl, sub_resource_idx, wined3d_debug_location(sub_resource->locations));
2487 return FALSE;
2490 static BOOL wined3d_texture_load_drawable(struct wined3d_texture *texture,
2491 unsigned int sub_resource_idx, struct wined3d_context *context)
2493 struct wined3d_device *device;
2494 unsigned int level;
2495 RECT r;
2497 if (texture->resource.bind_flags & WINED3D_BIND_DEPTH_STENCIL)
2499 DWORD current = texture->sub_resources[sub_resource_idx].locations;
2500 FIXME("Unimplemented copy from %s for depth/stencil buffers.\n",
2501 wined3d_debug_location(current));
2502 return FALSE;
2505 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO
2506 && wined3d_resource_is_offscreen(&texture->resource))
2508 ERR("Trying to load offscreen texture into WINED3D_LOCATION_DRAWABLE.\n");
2509 return FALSE;
2512 device = texture->resource.device;
2513 level = sub_resource_idx % texture->level_count;
2514 SetRect(&r, 0, 0, wined3d_texture_get_level_width(texture, level),
2515 wined3d_texture_get_level_height(texture, level));
2516 wined3d_texture_load_location(texture, sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB);
2517 device->blitter->ops->blitter_blit(device->blitter, WINED3D_BLIT_OP_COLOR_BLIT, context,
2518 texture, sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB, &r,
2519 texture, sub_resource_idx, WINED3D_LOCATION_DRAWABLE, &r,
2520 NULL, WINED3D_TEXF_POINT);
2522 return TRUE;
2525 static BOOL wined3d_texture_load_renderbuffer(struct wined3d_texture *texture,
2526 unsigned int sub_resource_idx, struct wined3d_context *context, DWORD dst_location)
2528 unsigned int level = sub_resource_idx % texture->level_count;
2529 const RECT rect = {0, 0,
2530 wined3d_texture_get_level_width(texture, level),
2531 wined3d_texture_get_level_height(texture, level)};
2532 struct wined3d_texture_sub_resource *sub_resource;
2533 DWORD src_location, locations;
2535 sub_resource = &texture->sub_resources[sub_resource_idx];
2536 locations = sub_resource->locations;
2537 if (texture->resource.bind_flags & WINED3D_BIND_DEPTH_STENCIL)
2539 FIXME("Unimplemented copy from %s for depth/stencil buffers.\n",
2540 wined3d_debug_location(locations));
2541 return FALSE;
2544 if (locations & WINED3D_LOCATION_RB_MULTISAMPLE)
2545 src_location = WINED3D_LOCATION_RB_MULTISAMPLE;
2546 else if (locations & WINED3D_LOCATION_RB_RESOLVED)
2547 src_location = WINED3D_LOCATION_RB_RESOLVED;
2548 else if (locations & WINED3D_LOCATION_TEXTURE_SRGB)
2549 src_location = WINED3D_LOCATION_TEXTURE_SRGB;
2550 else if (locations & WINED3D_LOCATION_TEXTURE_RGB)
2551 src_location = WINED3D_LOCATION_TEXTURE_RGB;
2552 else if (locations & WINED3D_LOCATION_DRAWABLE)
2553 src_location = WINED3D_LOCATION_DRAWABLE;
2554 else /* texture2d_blt_fbo() will load the source location if necessary. */
2555 src_location = WINED3D_LOCATION_TEXTURE_RGB;
2557 texture2d_blt_fbo(texture->resource.device, context, WINED3D_TEXF_POINT, texture,
2558 sub_resource_idx, src_location, &rect, texture, sub_resource_idx, dst_location, &rect);
2560 return TRUE;
2563 static BOOL wined3d_texture_gl_load_texture(struct wined3d_texture_gl *texture_gl,
2564 unsigned int sub_resource_idx, struct wined3d_context_gl *context_gl, BOOL srgb)
2566 unsigned int width, height, level, src_row_pitch, src_slice_pitch, dst_row_pitch, dst_slice_pitch;
2567 struct wined3d_device *device = texture_gl->t.resource.device;
2568 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
2569 const struct wined3d_color_key_conversion *conversion;
2570 struct wined3d_texture_sub_resource *sub_resource;
2571 const struct wined3d_format *format;
2572 struct wined3d_bo_address data;
2573 BYTE *src_mem, *dst_mem = NULL;
2574 struct wined3d_box src_box;
2575 DWORD dst_location;
2576 BOOL depth;
2578 depth = texture_gl->t.resource.bind_flags & WINED3D_BIND_DEPTH_STENCIL;
2579 sub_resource = &texture_gl->t.sub_resources[sub_resource_idx];
2581 if (!depth && wined3d_settings.offscreen_rendering_mode != ORM_FBO
2582 && wined3d_resource_is_offscreen(&texture_gl->t.resource)
2583 && (sub_resource->locations & WINED3D_LOCATION_DRAWABLE))
2585 texture2d_load_fb_texture(texture_gl, sub_resource_idx, srgb, &context_gl->c);
2587 return TRUE;
2590 level = sub_resource_idx % texture_gl->t.level_count;
2591 wined3d_texture_get_level_box(&texture_gl->t, level, &src_box);
2593 if (!depth && sub_resource->locations & (WINED3D_LOCATION_TEXTURE_SRGB | WINED3D_LOCATION_TEXTURE_RGB)
2594 && (texture_gl->t.resource.format_flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB)
2595 && fbo_blitter_supported(WINED3D_BLIT_OP_COLOR_BLIT, gl_info,
2596 &texture_gl->t.resource, WINED3D_LOCATION_TEXTURE_RGB,
2597 &texture_gl->t.resource, WINED3D_LOCATION_TEXTURE_SRGB))
2599 RECT src_rect;
2601 SetRect(&src_rect, src_box.left, src_box.top, src_box.right, src_box.bottom);
2602 if (srgb)
2603 texture2d_blt_fbo(device, &context_gl->c, WINED3D_TEXF_POINT,
2604 &texture_gl->t, sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB, &src_rect,
2605 &texture_gl->t, sub_resource_idx, WINED3D_LOCATION_TEXTURE_SRGB, &src_rect);
2606 else
2607 texture2d_blt_fbo(device, &context_gl->c, WINED3D_TEXF_POINT,
2608 &texture_gl->t, sub_resource_idx, WINED3D_LOCATION_TEXTURE_SRGB, &src_rect,
2609 &texture_gl->t, sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB, &src_rect);
2611 return TRUE;
2614 if (!depth && sub_resource->locations & (WINED3D_LOCATION_RB_MULTISAMPLE | WINED3D_LOCATION_RB_RESOLVED)
2615 && (!srgb || (texture_gl->t.resource.format_flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB)))
2617 DWORD src_location = sub_resource->locations & WINED3D_LOCATION_RB_RESOLVED ?
2618 WINED3D_LOCATION_RB_RESOLVED : WINED3D_LOCATION_RB_MULTISAMPLE;
2619 RECT src_rect;
2621 SetRect(&src_rect, src_box.left, src_box.top, src_box.right, src_box.bottom);
2622 dst_location = srgb ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB;
2623 if (fbo_blitter_supported(WINED3D_BLIT_OP_COLOR_BLIT, gl_info,
2624 &texture_gl->t.resource, src_location, &texture_gl->t.resource, dst_location))
2625 texture2d_blt_fbo(device, &context_gl->c, WINED3D_TEXF_POINT, &texture_gl->t, sub_resource_idx,
2626 src_location, &src_rect, &texture_gl->t, sub_resource_idx, dst_location, &src_rect);
2628 return TRUE;
2631 /* Upload from system memory */
2633 if (srgb)
2635 dst_location = WINED3D_LOCATION_TEXTURE_SRGB;
2636 if ((sub_resource->locations & (WINED3D_LOCATION_TEXTURE_RGB | texture_gl->t.resource.map_binding))
2637 == WINED3D_LOCATION_TEXTURE_RGB)
2639 FIXME_(d3d_perf)("Downloading RGB texture %p, %u to reload it as sRGB.\n", texture_gl, sub_resource_idx);
2640 wined3d_texture_load_location(&texture_gl->t, sub_resource_idx,
2641 &context_gl->c, texture_gl->t.resource.map_binding);
2644 else
2646 dst_location = WINED3D_LOCATION_TEXTURE_RGB;
2647 if ((sub_resource->locations & (WINED3D_LOCATION_TEXTURE_SRGB | texture_gl->t.resource.map_binding))
2648 == WINED3D_LOCATION_TEXTURE_SRGB)
2650 FIXME_(d3d_perf)("Downloading sRGB texture %p, %u to reload it as RGB.\n", texture_gl, sub_resource_idx);
2651 wined3d_texture_load_location(&texture_gl->t, sub_resource_idx,
2652 &context_gl->c, texture_gl->t.resource.map_binding);
2656 if (!(sub_resource->locations & wined3d_texture_sysmem_locations))
2658 WARN("Trying to load a texture from sysmem, but no simple location is valid.\n");
2659 /* Lets hope we get it from somewhere... */
2660 wined3d_texture_load_location(&texture_gl->t, sub_resource_idx, &context_gl->c, WINED3D_LOCATION_SYSMEM);
2663 wined3d_texture_get_pitch(&texture_gl->t, level, &src_row_pitch, &src_slice_pitch);
2665 format = texture_gl->t.resource.format;
2666 if ((conversion = wined3d_format_get_color_key_conversion(&texture_gl->t, TRUE)))
2667 format = wined3d_get_format(device->adapter, conversion->dst_format, texture_gl->t.resource.bind_flags);
2669 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
2670 * WINED3D_TEXTURE_CONVERTED but it isn't set (yet) in all cases it is
2671 * getting called. */
2672 if (conversion && sub_resource->buffer_object)
2674 TRACE("Removing the pbo attached to texture %p, %u.\n", texture_gl, sub_resource_idx);
2676 wined3d_texture_load_location(&texture_gl->t, sub_resource_idx, &context_gl->c, WINED3D_LOCATION_SYSMEM);
2677 wined3d_texture_set_map_binding(&texture_gl->t, WINED3D_LOCATION_SYSMEM);
2680 wined3d_texture_get_memory(&texture_gl->t, sub_resource_idx, &data, sub_resource->locations);
2681 if (conversion)
2683 width = src_box.right - src_box.left;
2684 height = src_box.bottom - src_box.top;
2685 wined3d_format_calculate_pitch(format, device->surface_alignment,
2686 width, height, &dst_row_pitch, &dst_slice_pitch);
2688 src_mem = wined3d_context_gl_map_bo_address(context_gl, &data,
2689 src_slice_pitch, GL_PIXEL_UNPACK_BUFFER, WINED3D_MAP_READ);
2690 if (!(dst_mem = heap_alloc(dst_slice_pitch)))
2692 ERR("Out of memory (%u).\n", dst_slice_pitch);
2693 return FALSE;
2695 conversion->convert(src_mem, src_row_pitch, dst_mem, dst_row_pitch,
2696 width, height, &texture_gl->t.async.gl_color_key);
2697 src_row_pitch = dst_row_pitch;
2698 src_slice_pitch = dst_slice_pitch;
2699 wined3d_context_gl_unmap_bo_address(context_gl, &data, GL_PIXEL_UNPACK_BUFFER);
2701 data.buffer_object = 0;
2702 data.addr = dst_mem;
2705 wined3d_texture_gl_upload_data(&context_gl->c, wined3d_const_bo_address(&data), format, &src_box,
2706 src_row_pitch, src_slice_pitch, &texture_gl->t, sub_resource_idx, dst_location, 0, 0, 0);
2708 heap_free(dst_mem);
2710 return TRUE;
2713 static BOOL wined3d_texture_gl_prepare_location(struct wined3d_texture *texture,
2714 unsigned int sub_resource_idx, struct wined3d_context *context, unsigned int location)
2716 struct wined3d_texture_gl *texture_gl = wined3d_texture_gl(texture);
2717 struct wined3d_context_gl *context_gl = wined3d_context_gl(context);
2719 switch (location)
2721 case WINED3D_LOCATION_SYSMEM:
2722 return wined3d_resource_prepare_sysmem(&texture->resource);
2724 case WINED3D_LOCATION_USER_MEMORY:
2725 if (!texture->user_memory)
2726 ERR("Preparing WINED3D_LOCATION_USER_MEMORY, but texture->user_memory is NULL.\n");
2727 return TRUE;
2729 case WINED3D_LOCATION_BUFFER:
2730 wined3d_texture_prepare_buffer_object(texture, sub_resource_idx, context_gl->gl_info);
2731 return TRUE;
2733 case WINED3D_LOCATION_TEXTURE_RGB:
2734 wined3d_texture_gl_prepare_texture(texture_gl, context_gl, FALSE);
2735 return TRUE;
2737 case WINED3D_LOCATION_TEXTURE_SRGB:
2738 wined3d_texture_gl_prepare_texture(texture_gl, context_gl, TRUE);
2739 return TRUE;
2741 case WINED3D_LOCATION_DRAWABLE:
2742 if (!texture->swapchain && wined3d_settings.offscreen_rendering_mode != ORM_BACKBUFFER)
2743 ERR("Texture %p does not have a drawable.\n", texture);
2744 return TRUE;
2746 case WINED3D_LOCATION_RB_MULTISAMPLE:
2747 wined3d_texture_gl_prepare_rb(texture_gl, context_gl->gl_info, TRUE);
2748 return TRUE;
2750 case WINED3D_LOCATION_RB_RESOLVED:
2751 wined3d_texture_gl_prepare_rb(texture_gl, context_gl->gl_info, FALSE);
2752 return TRUE;
2754 default:
2755 ERR("Invalid location %s.\n", wined3d_debug_location(location));
2756 return FALSE;
2760 /* Context activation is done by the caller. */
2761 static BOOL wined3d_texture_gl_load_location(struct wined3d_texture *texture,
2762 unsigned int sub_resource_idx, struct wined3d_context *context, DWORD location)
2764 struct wined3d_texture_gl *texture_gl = wined3d_texture_gl(texture);
2765 struct wined3d_context_gl *context_gl = wined3d_context_gl(context);
2767 TRACE("texture %p, sub_resource_idx %u, context %p, location %s.\n",
2768 texture, sub_resource_idx, context, wined3d_debug_location(location));
2770 if (!wined3d_texture_gl_prepare_location(texture, sub_resource_idx, context, location))
2771 return FALSE;
2773 switch (location)
2775 case WINED3D_LOCATION_USER_MEMORY:
2776 case WINED3D_LOCATION_SYSMEM:
2777 case WINED3D_LOCATION_BUFFER:
2778 return wined3d_texture_gl_load_sysmem(texture_gl, sub_resource_idx, context_gl, location);
2780 case WINED3D_LOCATION_DRAWABLE:
2781 return wined3d_texture_load_drawable(texture, sub_resource_idx, context);
2783 case WINED3D_LOCATION_RB_RESOLVED:
2784 case WINED3D_LOCATION_RB_MULTISAMPLE:
2785 return wined3d_texture_load_renderbuffer(texture, sub_resource_idx, context, location);
2787 case WINED3D_LOCATION_TEXTURE_RGB:
2788 case WINED3D_LOCATION_TEXTURE_SRGB:
2789 return wined3d_texture_gl_load_texture(texture_gl, sub_resource_idx,
2790 context_gl, location == WINED3D_LOCATION_TEXTURE_SRGB);
2792 default:
2793 FIXME("Unhandled %s load from %s.\n", wined3d_debug_location(location),
2794 wined3d_debug_location(texture->sub_resources[sub_resource_idx].locations));
2795 return FALSE;
2799 static const struct wined3d_texture_ops texture_gl_ops =
2801 wined3d_texture_gl_prepare_location,
2802 wined3d_texture_gl_load_location,
2803 wined3d_texture_gl_upload_data,
2804 wined3d_texture_gl_download_data,
2807 struct wined3d_texture * __cdecl wined3d_texture_from_resource(struct wined3d_resource *resource)
2809 return texture_from_resource(resource);
2812 static ULONG texture_resource_incref(struct wined3d_resource *resource)
2814 return wined3d_texture_incref(texture_from_resource(resource));
2817 static ULONG texture_resource_decref(struct wined3d_resource *resource)
2819 return wined3d_texture_decref(texture_from_resource(resource));
2822 static void texture_resource_preload(struct wined3d_resource *resource)
2824 struct wined3d_texture *texture = texture_from_resource(resource);
2825 struct wined3d_context *context;
2827 context = context_acquire(resource->device, NULL, 0);
2828 wined3d_texture_load(texture, context, texture->flags & WINED3D_TEXTURE_IS_SRGB);
2829 context_release(context);
2832 static void wined3d_texture_gl_unload(struct wined3d_resource *resource)
2834 struct wined3d_texture_gl *texture_gl = wined3d_texture_gl(texture_from_resource(resource));
2835 UINT sub_count = texture_gl->t.level_count * texture_gl->t.layer_count;
2836 struct wined3d_renderbuffer_entry *entry, *entry2;
2837 struct wined3d_device *device = resource->device;
2838 const struct wined3d_gl_info *gl_info;
2839 struct wined3d_context *context;
2840 UINT i;
2842 TRACE("texture_gl %p.\n", texture_gl);
2844 context = context_acquire(device, NULL, 0);
2845 gl_info = wined3d_context_gl(context)->gl_info;
2847 for (i = 0; i < sub_count; ++i)
2849 struct wined3d_texture_sub_resource *sub_resource = &texture_gl->t.sub_resources[i];
2851 if (resource->access & WINED3D_RESOURCE_ACCESS_CPU
2852 && wined3d_texture_load_location(&texture_gl->t, i, context, resource->map_binding))
2854 wined3d_texture_invalidate_location(&texture_gl->t, i, ~resource->map_binding);
2856 else
2858 /* We should only get here on device reset/teardown for implicit
2859 * resources. */
2860 if (resource->access & WINED3D_RESOURCE_ACCESS_CPU
2861 || resource->type != WINED3D_RTYPE_TEXTURE_2D)
2862 ERR("Discarding %s %p sub-resource %u with resource access %s.\n",
2863 debug_d3dresourcetype(resource->type), resource, i,
2864 wined3d_debug_resource_access(resource->access));
2865 wined3d_texture_validate_location(&texture_gl->t, i, WINED3D_LOCATION_DISCARDED);
2866 wined3d_texture_invalidate_location(&texture_gl->t, i, ~WINED3D_LOCATION_DISCARDED);
2869 if (sub_resource->buffer_object)
2870 wined3d_texture_remove_buffer_object(&texture_gl->t, i, gl_info);
2873 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &texture_gl->renderbuffers, struct wined3d_renderbuffer_entry, entry)
2875 context_gl_resource_released(device, entry->id, TRUE);
2876 gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id);
2877 list_remove(&entry->entry);
2878 heap_free(entry);
2880 list_init(&texture_gl->renderbuffers);
2881 texture_gl->current_renderbuffer = NULL;
2883 context_release(context);
2885 wined3d_texture_force_reload(&texture_gl->t);
2886 wined3d_texture_gl_unload_texture(texture_gl);
2889 static HRESULT texture_resource_sub_resource_map(struct wined3d_resource *resource, unsigned int sub_resource_idx,
2890 struct wined3d_map_desc *map_desc, const struct wined3d_box *box, DWORD flags)
2892 const struct wined3d_format *format = resource->format;
2893 struct wined3d_texture_sub_resource *sub_resource;
2894 struct wined3d_device *device = resource->device;
2895 unsigned int fmt_flags = resource->format_flags;
2896 struct wined3d_context *context;
2897 struct wined3d_texture *texture;
2898 struct wined3d_bo_address data;
2899 unsigned int texture_level;
2900 BYTE *base_memory;
2901 BOOL ret;
2903 TRACE("resource %p, sub_resource_idx %u, map_desc %p, box %s, flags %#x.\n",
2904 resource, sub_resource_idx, map_desc, debug_box(box), flags);
2906 texture = texture_from_resource(resource);
2907 if (!(sub_resource = wined3d_texture_get_sub_resource(texture, sub_resource_idx)))
2908 return E_INVALIDARG;
2910 texture_level = sub_resource_idx % texture->level_count;
2911 if (box && FAILED(wined3d_texture_check_box_dimensions(texture, texture_level, box)))
2913 WARN("Map box is invalid.\n");
2914 if (((fmt_flags & WINED3DFMT_FLAG_BLOCKS) && !(resource->access & WINED3D_RESOURCE_ACCESS_CPU))
2915 || resource->type != WINED3D_RTYPE_TEXTURE_2D)
2916 return WINED3DERR_INVALIDCALL;
2919 if (texture->flags & WINED3D_TEXTURE_DC_IN_USE)
2921 WARN("DC is in use.\n");
2922 return WINED3DERR_INVALIDCALL;
2925 if (sub_resource->map_count)
2927 WARN("Sub-resource is already mapped.\n");
2928 return WINED3DERR_INVALIDCALL;
2931 context = context_acquire(device, NULL, 0);
2933 if (flags & WINED3D_MAP_DISCARD)
2935 TRACE("WINED3D_MAP_DISCARD flag passed, marking %s as up to date.\n",
2936 wined3d_debug_location(resource->map_binding));
2937 if ((ret = wined3d_texture_prepare_location(texture, sub_resource_idx, context, resource->map_binding)))
2938 wined3d_texture_validate_location(texture, sub_resource_idx, resource->map_binding);
2940 else
2942 if (resource->usage & WINED3DUSAGE_DYNAMIC)
2943 WARN_(d3d_perf)("Mapping a dynamic texture without WINED3D_MAP_DISCARD.\n");
2944 ret = wined3d_texture_load_location(texture, sub_resource_idx, context, resource->map_binding);
2947 if (!ret)
2949 ERR("Failed to prepare location.\n");
2950 context_release(context);
2951 return E_OUTOFMEMORY;
2954 if (flags & WINED3D_MAP_WRITE
2955 && (!(flags & WINED3D_MAP_NO_DIRTY_UPDATE) || (resource->usage & WINED3DUSAGE_DYNAMIC)))
2956 wined3d_texture_invalidate_location(texture, sub_resource_idx, ~resource->map_binding);
2958 wined3d_texture_get_memory(texture, sub_resource_idx, &data, resource->map_binding);
2959 base_memory = wined3d_context_map_bo_address(context, &data,
2960 sub_resource->size, GL_PIXEL_UNPACK_BUFFER, flags);
2961 TRACE("Base memory pointer %p.\n", base_memory);
2963 context_release(context);
2965 if (fmt_flags & WINED3DFMT_FLAG_BROKEN_PITCH)
2967 map_desc->row_pitch = wined3d_texture_get_level_width(texture, texture_level) * format->byte_count;
2968 map_desc->slice_pitch = wined3d_texture_get_level_height(texture, texture_level) * map_desc->row_pitch;
2970 else
2972 wined3d_texture_get_pitch(texture, texture_level, &map_desc->row_pitch, &map_desc->slice_pitch);
2975 if (!box)
2977 map_desc->data = base_memory;
2979 else
2981 if ((fmt_flags & (WINED3DFMT_FLAG_BLOCKS | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_BLOCKS)
2983 /* Compressed textures are block based, so calculate the offset of
2984 * the block that contains the top-left pixel of the mapped box. */
2985 map_desc->data = base_memory
2986 + (box->front * map_desc->slice_pitch)
2987 + ((box->top / format->block_height) * map_desc->row_pitch)
2988 + ((box->left / format->block_width) * format->block_byte_count);
2990 else
2992 map_desc->data = base_memory
2993 + (box->front * map_desc->slice_pitch)
2994 + (box->top * map_desc->row_pitch)
2995 + (box->left * format->byte_count);
2999 if (texture->swapchain && texture->swapchain->front_buffer == texture)
3001 RECT *r = &texture->swapchain->front_buffer_update;
3003 if (!box)
3004 SetRect(r, 0, 0, resource->width, resource->height);
3005 else
3006 SetRect(r, box->left, box->top, box->right, box->bottom);
3007 TRACE("Mapped front buffer %s.\n", wine_dbgstr_rect(r));
3010 ++resource->map_count;
3011 ++sub_resource->map_count;
3013 TRACE("Returning memory %p, row pitch %u, slice pitch %u.\n",
3014 map_desc->data, map_desc->row_pitch, map_desc->slice_pitch);
3016 return WINED3D_OK;
3019 static HRESULT texture_resource_sub_resource_unmap(struct wined3d_resource *resource, unsigned int sub_resource_idx)
3021 struct wined3d_texture_sub_resource *sub_resource;
3022 struct wined3d_device *device = resource->device;
3023 struct wined3d_context *context;
3024 struct wined3d_texture *texture;
3025 struct wined3d_bo_address data;
3027 TRACE("resource %p, sub_resource_idx %u.\n", resource, sub_resource_idx);
3029 texture = texture_from_resource(resource);
3030 if (!(sub_resource = wined3d_texture_get_sub_resource(texture, sub_resource_idx)))
3031 return E_INVALIDARG;
3033 if (!sub_resource->map_count)
3035 WARN("Trying to unmap unmapped sub-resource.\n");
3036 if (texture->flags & WINED3D_TEXTURE_DC_IN_USE)
3037 return WINED3D_OK;
3038 return WINEDDERR_NOTLOCKED;
3041 context = context_acquire(device, NULL, 0);
3043 wined3d_texture_get_memory(texture, sub_resource_idx, &data, texture->resource.map_binding);
3044 wined3d_context_unmap_bo_address(context, &data, GL_PIXEL_UNPACK_BUFFER);
3046 context_release(context);
3048 if (texture->swapchain && texture->swapchain->front_buffer == texture)
3050 if (!(sub_resource->locations & (WINED3D_LOCATION_DRAWABLE | WINED3D_LOCATION_TEXTURE_RGB)))
3051 texture->swapchain->swapchain_ops->swapchain_frontbuffer_updated(texture->swapchain);
3054 --sub_resource->map_count;
3055 if (!--resource->map_count && texture->update_map_binding)
3056 wined3d_texture_update_map_binding(texture);
3058 return WINED3D_OK;
3061 static const struct wined3d_resource_ops texture_resource_ops =
3063 texture_resource_incref,
3064 texture_resource_decref,
3065 texture_resource_preload,
3066 wined3d_texture_gl_unload,
3067 texture_resource_sub_resource_map,
3068 texture_resource_sub_resource_unmap,
3071 static HRESULT wined3d_texture_init(struct wined3d_texture *texture, const struct wined3d_resource_desc *desc,
3072 unsigned int layer_count, unsigned int level_count, DWORD flags, struct wined3d_device *device,
3073 void *parent, const struct wined3d_parent_ops *parent_ops, void *sub_resources,
3074 const struct wined3d_texture_ops *texture_ops)
3076 const struct wined3d_d3d_info *d3d_info = &device->adapter->d3d_info;
3077 struct wined3d_device_parent *device_parent = device->device_parent;
3078 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
3079 unsigned int sub_count, i, j, size, offset = 0;
3080 unsigned int pow2_width, pow2_height;
3081 const struct wined3d_format *format;
3082 HRESULT hr;
3084 TRACE("texture %p, resource_type %s, format %s, multisample_type %#x, multisample_quality %#x, "
3085 "usage %s, access %s, width %u, height %u, depth %u, layer_count %u, level_count %u, "
3086 "flags %#x, device %p, parent %p, parent_ops %p, sub_resources %p, texture_ops %p.\n",
3087 texture, debug_d3dresourcetype(desc->resource_type), debug_d3dformat(desc->format),
3088 desc->multisample_type, desc->multisample_quality, debug_d3dusage(desc->usage),
3089 wined3d_debug_resource_access(desc->access), desc->width, desc->height, desc->depth,
3090 layer_count, level_count, flags, device, parent, parent_ops, sub_resources, texture_ops);
3092 if (!desc->width || !desc->height || !desc->depth)
3093 return WINED3DERR_INVALIDCALL;
3095 if (desc->resource_type == WINED3D_RTYPE_TEXTURE_3D && layer_count != 1)
3097 ERR("Invalid layer count for volume texture.\n");
3098 return E_INVALIDARG;
3101 texture->sub_resources = sub_resources;
3103 /* TODO: It should only be possible to create textures for formats
3104 * that are reported as supported. */
3105 if (WINED3DFMT_UNKNOWN >= desc->format)
3107 WARN("Texture cannot be created with a format of WINED3DFMT_UNKNOWN.\n");
3108 return WINED3DERR_INVALIDCALL;
3110 format = wined3d_get_format(device->adapter, desc->format, desc->bind_flags);
3112 if (desc->usage & WINED3DUSAGE_DYNAMIC && (wined3d_resource_access_is_managed(desc->access)
3113 || desc->usage & WINED3DUSAGE_SCRATCH))
3115 WARN("Attempted to create a dynamic texture with access %s and usage %s.\n",
3116 wined3d_debug_resource_access(desc->access), debug_d3dusage(desc->usage));
3117 return WINED3DERR_INVALIDCALL;
3120 pow2_width = desc->width;
3121 pow2_height = desc->height;
3122 if (((desc->width & (desc->width - 1)) || (desc->height & (desc->height - 1)) || (desc->depth & (desc->depth - 1)))
3123 && !d3d_info->texture_npot)
3125 /* level_count == 0 returns an error as well. */
3126 if (level_count != 1 || layer_count != 1 || desc->resource_type == WINED3D_RTYPE_TEXTURE_3D)
3128 if (!(desc->usage & WINED3DUSAGE_SCRATCH))
3130 WARN("Attempted to create a mipmapped/cube/array/volume NPOT "
3131 "texture without unconditional NPOT support.\n");
3132 return WINED3DERR_INVALIDCALL;
3135 WARN("Creating a scratch mipmapped/cube/array NPOT texture despite lack of HW support.\n");
3137 texture->flags |= WINED3D_TEXTURE_COND_NP2;
3139 if (desc->resource_type != WINED3D_RTYPE_TEXTURE_3D && !d3d_info->texture_npot_conditional)
3141 /* TODO: Add support for non-power-of-two compressed textures. */
3142 if (format->flags[WINED3D_GL_RES_TYPE_TEX_2D]
3143 & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_HEIGHT_SCALE))
3145 FIXME("Compressed or height scaled non-power-of-two (%ux%u) textures are not supported.\n",
3146 desc->width, desc->height);
3147 return WINED3DERR_NOTAVAILABLE;
3150 /* Find the nearest pow2 match. */
3151 pow2_width = pow2_height = 1;
3152 while (pow2_width < desc->width)
3153 pow2_width <<= 1;
3154 while (pow2_height < desc->height)
3155 pow2_height <<= 1;
3156 texture->flags |= WINED3D_TEXTURE_COND_NP2_EMULATED;
3159 texture->pow2_width = pow2_width;
3160 texture->pow2_height = pow2_height;
3162 if ((pow2_width > d3d_info->limits.texture_size || pow2_height > d3d_info->limits.texture_size)
3163 && (desc->bind_flags & WINED3D_BIND_SHADER_RESOURCE))
3165 /* One of four options:
3166 * 1: Do the same as we do with NPOT and scale the texture. (Any
3167 * texture ops would require the texture to be scaled which is
3168 * potentially slow.)
3169 * 2: Set the texture to the maximum size (bad idea).
3170 * 3: WARN and return WINED3DERR_NOTAVAILABLE.
3171 * 4: Create the surface, but allow it to be used only for DirectDraw
3172 * Blts. Some apps (e.g. Swat 3) create textures with a height of
3173 * 16 and a width > 3000 and blt 16x16 letter areas from them to
3174 * the render target. */
3175 if (desc->access & WINED3D_RESOURCE_ACCESS_GPU)
3177 WARN("Dimensions (%ux%u) exceed the maximum texture size.\n", pow2_width, pow2_height);
3178 return WINED3DERR_NOTAVAILABLE;
3181 /* We should never use this surface in combination with OpenGL. */
3182 TRACE("Creating an oversized (%ux%u) surface.\n", pow2_width, pow2_height);
3185 for (i = 0; i < layer_count; ++i)
3187 for (j = 0; j < level_count; ++j)
3189 unsigned int idx = i * level_count + j;
3191 size = wined3d_format_calculate_size(format, device->surface_alignment,
3192 max(1, desc->width >> j), max(1, desc->height >> j), max(1, desc->depth >> j));
3193 texture->sub_resources[idx].offset = offset;
3194 texture->sub_resources[idx].size = size;
3195 offset += size;
3197 offset = (offset + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1);
3200 if (!offset)
3201 return WINED3DERR_INVALIDCALL;
3203 if (FAILED(hr = resource_init(&texture->resource, device, desc->resource_type, format,
3204 desc->multisample_type, desc->multisample_quality, desc->usage, desc->bind_flags, desc->access,
3205 desc->width, desc->height, desc->depth, offset, parent, parent_ops, &texture_resource_ops)))
3207 static unsigned int once;
3209 /* DXTn 3D textures are not supported. Do not write the ERR for them. */
3210 if ((desc->format == WINED3DFMT_DXT1 || desc->format == WINED3DFMT_DXT2 || desc->format == WINED3DFMT_DXT3
3211 || desc->format == WINED3DFMT_DXT4 || desc->format == WINED3DFMT_DXT5)
3212 && !(format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_TEXTURE)
3213 && desc->resource_type != WINED3D_RTYPE_TEXTURE_3D && !once++)
3214 ERR_(winediag)("The application tried to create a DXTn texture, but the driver does not support them.\n");
3216 WARN("Failed to initialize resource, returning %#x\n", hr);
3217 return hr;
3219 wined3d_resource_update_draw_binding(&texture->resource);
3221 texture->texture_ops = texture_ops;
3223 texture->layer_count = layer_count;
3224 texture->level_count = level_count;
3225 texture->lod = 0;
3226 texture->flags |= WINED3D_TEXTURE_POW2_MAT_IDENT | WINED3D_TEXTURE_NORMALIZED_COORDS;
3227 if (flags & WINED3D_TEXTURE_CREATE_GET_DC_LENIENT)
3228 texture->flags |= WINED3D_TEXTURE_PIN_SYSMEM | WINED3D_TEXTURE_GET_DC_LENIENT;
3229 if (flags & (WINED3D_TEXTURE_CREATE_GET_DC | WINED3D_TEXTURE_CREATE_GET_DC_LENIENT))
3230 texture->flags |= WINED3D_TEXTURE_GET_DC;
3231 if (flags & WINED3D_TEXTURE_CREATE_DISCARD)
3232 texture->flags |= WINED3D_TEXTURE_DISCARD;
3233 if (flags & WINED3D_TEXTURE_CREATE_GENERATE_MIPMAPS)
3235 if (!(texture->resource.format_flags & WINED3DFMT_FLAG_GEN_MIPMAP))
3236 WARN("Format doesn't support mipmaps generation, "
3237 "ignoring WINED3D_TEXTURE_CREATE_GENERATE_MIPMAPS flag.\n");
3238 else
3239 texture->flags |= WINED3D_TEXTURE_GENERATE_MIPMAPS;
3242 /* Precalculated scaling for 'faked' non power of two texture coords. */
3243 if (texture->resource.gl_type == WINED3D_GL_RES_TYPE_TEX_RECT)
3245 texture->pow2_matrix[0] = (float)desc->width;
3246 texture->pow2_matrix[5] = (float)desc->height;
3247 texture->flags &= ~(WINED3D_TEXTURE_POW2_MAT_IDENT | WINED3D_TEXTURE_NORMALIZED_COORDS);
3249 else if (texture->flags & WINED3D_TEXTURE_COND_NP2_EMULATED)
3251 texture->pow2_matrix[0] = (((float)desc->width) / ((float)pow2_width));
3252 texture->pow2_matrix[5] = (((float)desc->height) / ((float)pow2_height));
3253 texture->flags &= ~WINED3D_TEXTURE_POW2_MAT_IDENT;
3255 else
3257 texture->pow2_matrix[0] = 1.0f;
3258 texture->pow2_matrix[5] = 1.0f;
3260 texture->pow2_matrix[10] = 1.0f;
3261 texture->pow2_matrix[15] = 1.0f;
3262 TRACE("x scale %.8e, y scale %.8e.\n", texture->pow2_matrix[0], texture->pow2_matrix[5]);
3264 if (wined3d_texture_use_pbo(texture, gl_info))
3265 texture->resource.map_binding = WINED3D_LOCATION_BUFFER;
3267 if (desc->resource_type != WINED3D_RTYPE_TEXTURE_3D
3268 || !wined3d_texture_use_pbo(texture, gl_info))
3270 if (!wined3d_resource_prepare_sysmem(&texture->resource))
3272 wined3d_texture_cleanup_sync(texture);
3273 return E_OUTOFMEMORY;
3277 sub_count = level_count * layer_count;
3278 if (sub_count / layer_count != level_count)
3280 wined3d_texture_cleanup_sync(texture);
3281 return E_OUTOFMEMORY;
3284 if (desc->usage & WINED3DUSAGE_OVERLAY)
3286 if (!(texture->overlay_info = heap_calloc(sub_count, sizeof(*texture->overlay_info))))
3288 wined3d_texture_cleanup_sync(texture);
3289 return E_OUTOFMEMORY;
3292 for (i = 0; i < sub_count; ++i)
3294 list_init(&texture->overlay_info[i].entry);
3295 list_init(&texture->overlay_info[i].overlays);
3299 /* Generate all sub-resources. */
3300 for (i = 0; i < sub_count; ++i)
3302 struct wined3d_texture_sub_resource *sub_resource;
3304 sub_resource = &texture->sub_resources[i];
3305 sub_resource->locations = WINED3D_LOCATION_DISCARDED;
3306 if (desc->resource_type != WINED3D_RTYPE_TEXTURE_3D)
3308 wined3d_texture_validate_location(texture, i, WINED3D_LOCATION_SYSMEM);
3309 wined3d_texture_invalidate_location(texture, i, ~WINED3D_LOCATION_SYSMEM);
3312 if (FAILED(hr = device_parent->ops->texture_sub_resource_created(device_parent,
3313 desc->resource_type, texture, i, &sub_resource->parent, &sub_resource->parent_ops)))
3315 WARN("Failed to create sub-resource parent, hr %#x.\n", hr);
3316 sub_resource->parent = NULL;
3317 wined3d_texture_cleanup_sync(texture);
3318 return hr;
3321 TRACE("parent %p, parent_ops %p.\n", sub_resource->parent, sub_resource->parent_ops);
3323 TRACE("Created sub-resource %u (level %u, layer %u).\n",
3324 i, i % texture->level_count, i / texture->level_count);
3326 if (desc->usage & WINED3DUSAGE_OWNDC)
3328 struct wined3d_texture_idx texture_idx = {texture, i};
3330 wined3d_cs_init_object(device->cs, wined3d_texture_create_dc, &texture_idx);
3331 wined3d_cs_finish(device->cs, WINED3D_CS_QUEUE_DEFAULT);
3332 if (!texture->dc_info || !texture->dc_info[i].dc)
3334 wined3d_texture_cleanup_sync(texture);
3335 return WINED3DERR_INVALIDCALL;
3340 return WINED3D_OK;
3343 HRESULT CDECL wined3d_texture_blt(struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx,
3344 const RECT *dst_rect, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
3345 const RECT *src_rect, DWORD flags, const struct wined3d_blt_fx *fx, enum wined3d_texture_filter_type filter)
3347 struct wined3d_box src_box = {src_rect->left, src_rect->top, src_rect->right, src_rect->bottom, 0, 1};
3348 struct wined3d_box dst_box = {dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, 0, 1};
3349 unsigned int dst_format_flags, src_format_flags = 0;
3350 HRESULT hr;
3352 TRACE("dst_texture %p, dst_sub_resource_idx %u, dst_rect %s, src_texture %p, "
3353 "src_sub_resource_idx %u, src_rect %s, flags %#x, fx %p, filter %s.\n",
3354 dst_texture, dst_sub_resource_idx, wine_dbgstr_rect(dst_rect), src_texture,
3355 src_sub_resource_idx, wine_dbgstr_rect(src_rect), flags, fx, debug_d3dtexturefiltertype(filter));
3357 if (dst_sub_resource_idx >= dst_texture->level_count * dst_texture->layer_count
3358 || dst_texture->resource.type != WINED3D_RTYPE_TEXTURE_2D)
3359 return WINED3DERR_INVALIDCALL;
3361 if (src_sub_resource_idx >= src_texture->level_count * src_texture->layer_count
3362 || src_texture->resource.type != WINED3D_RTYPE_TEXTURE_2D)
3363 return WINED3DERR_INVALIDCALL;
3365 dst_format_flags = dst_texture->resource.format_flags;
3366 if (FAILED(hr = wined3d_texture_check_box_dimensions(dst_texture,
3367 dst_sub_resource_idx % dst_texture->level_count, &dst_box)))
3368 return hr;
3370 src_format_flags = src_texture->resource.format_flags;
3371 if (FAILED(hr = wined3d_texture_check_box_dimensions(src_texture,
3372 src_sub_resource_idx % src_texture->level_count, &src_box)))
3373 return hr;
3375 if (dst_texture->sub_resources[dst_sub_resource_idx].map_count
3376 || src_texture->sub_resources[src_sub_resource_idx].map_count)
3378 WARN("Sub-resource is busy, returning WINEDDERR_SURFACEBUSY.\n");
3379 return WINEDDERR_SURFACEBUSY;
3382 if ((src_format_flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL))
3383 != (dst_format_flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)))
3385 WARN("Rejecting depth/stencil blit between incompatible formats.\n");
3386 return WINED3DERR_INVALIDCALL;
3389 if (dst_texture->resource.device != src_texture->resource.device)
3391 FIXME("Rejecting cross-device blit.\n");
3392 return E_NOTIMPL;
3395 wined3d_cs_emit_blt_sub_resource(dst_texture->resource.device->cs, &dst_texture->resource, dst_sub_resource_idx,
3396 &dst_box, &src_texture->resource, src_sub_resource_idx, &src_box, flags, fx, filter);
3398 return WINED3D_OK;
3401 HRESULT CDECL wined3d_texture_get_overlay_position(const struct wined3d_texture *texture,
3402 unsigned int sub_resource_idx, LONG *x, LONG *y)
3404 struct wined3d_overlay_info *overlay;
3406 TRACE("texture %p, sub_resource_idx %u, x %p, y %p.\n", texture, sub_resource_idx, x, y);
3408 if (!(texture->resource.usage & WINED3DUSAGE_OVERLAY)
3409 || sub_resource_idx >= texture->level_count * texture->layer_count)
3411 WARN("Invalid sub-resource specified.\n");
3412 return WINEDDERR_NOTAOVERLAYSURFACE;
3415 overlay = &texture->overlay_info[sub_resource_idx];
3416 if (!overlay->dst_texture)
3418 TRACE("Overlay not visible.\n");
3419 *x = 0;
3420 *y = 0;
3421 return WINEDDERR_OVERLAYNOTVISIBLE;
3424 *x = overlay->dst_rect.left;
3425 *y = overlay->dst_rect.top;
3427 TRACE("Returning position %d, %d.\n", *x, *y);
3429 return WINED3D_OK;
3432 HRESULT CDECL wined3d_texture_set_overlay_position(struct wined3d_texture *texture,
3433 unsigned int sub_resource_idx, LONG x, LONG y)
3435 struct wined3d_overlay_info *overlay;
3436 LONG w, h;
3438 TRACE("texture %p, sub_resource_idx %u, x %d, y %d.\n", texture, sub_resource_idx, x, y);
3440 if (!(texture->resource.usage & WINED3DUSAGE_OVERLAY)
3441 || sub_resource_idx >= texture->level_count * texture->layer_count)
3443 WARN("Invalid sub-resource specified.\n");
3444 return WINEDDERR_NOTAOVERLAYSURFACE;
3447 overlay = &texture->overlay_info[sub_resource_idx];
3448 w = overlay->dst_rect.right - overlay->dst_rect.left;
3449 h = overlay->dst_rect.bottom - overlay->dst_rect.top;
3450 SetRect(&overlay->dst_rect, x, y, x + w, y + h);
3452 return WINED3D_OK;
3455 HRESULT CDECL wined3d_texture_update_overlay(struct wined3d_texture *texture, unsigned int sub_resource_idx,
3456 const RECT *src_rect, struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx,
3457 const RECT *dst_rect, DWORD flags)
3459 struct wined3d_overlay_info *overlay;
3460 unsigned int level, dst_level;
3462 TRACE("texture %p, sub_resource_idx %u, src_rect %s, dst_texture %p, "
3463 "dst_sub_resource_idx %u, dst_rect %s, flags %#x.\n",
3464 texture, sub_resource_idx, wine_dbgstr_rect(src_rect), dst_texture,
3465 dst_sub_resource_idx, wine_dbgstr_rect(dst_rect), flags);
3467 if (!(texture->resource.usage & WINED3DUSAGE_OVERLAY) || texture->resource.type != WINED3D_RTYPE_TEXTURE_2D
3468 || sub_resource_idx >= texture->level_count * texture->layer_count)
3470 WARN("Invalid sub-resource specified.\n");
3471 return WINEDDERR_NOTAOVERLAYSURFACE;
3474 if (!dst_texture || dst_texture->resource.type != WINED3D_RTYPE_TEXTURE_2D
3475 || dst_sub_resource_idx >= dst_texture->level_count * dst_texture->layer_count)
3477 WARN("Invalid destination sub-resource specified.\n");
3478 return WINED3DERR_INVALIDCALL;
3481 overlay = &texture->overlay_info[sub_resource_idx];
3483 level = sub_resource_idx % texture->level_count;
3484 if (src_rect)
3485 overlay->src_rect = *src_rect;
3486 else
3487 SetRect(&overlay->src_rect, 0, 0,
3488 wined3d_texture_get_level_width(texture, level),
3489 wined3d_texture_get_level_height(texture, level));
3491 dst_level = dst_sub_resource_idx % dst_texture->level_count;
3492 if (dst_rect)
3493 overlay->dst_rect = *dst_rect;
3494 else
3495 SetRect(&overlay->dst_rect, 0, 0,
3496 wined3d_texture_get_level_width(dst_texture, dst_level),
3497 wined3d_texture_get_level_height(dst_texture, dst_level));
3499 if (overlay->dst_texture && (overlay->dst_texture != dst_texture
3500 || overlay->dst_sub_resource_idx != dst_sub_resource_idx || flags & WINEDDOVER_HIDE))
3502 overlay->dst_texture = NULL;
3503 list_remove(&overlay->entry);
3506 if (flags & WINEDDOVER_SHOW)
3508 if (overlay->dst_texture != dst_texture || overlay->dst_sub_resource_idx != dst_sub_resource_idx)
3510 overlay->dst_texture = dst_texture;
3511 overlay->dst_sub_resource_idx = dst_sub_resource_idx;
3512 list_add_tail(&texture->overlay_info[dst_sub_resource_idx].overlays, &overlay->entry);
3515 else if (flags & WINEDDOVER_HIDE)
3517 /* Tests show that the rectangles are erased on hide. */
3518 SetRectEmpty(&overlay->src_rect);
3519 SetRectEmpty(&overlay->dst_rect);
3520 overlay->dst_texture = NULL;
3523 return WINED3D_OK;
3526 void * CDECL wined3d_texture_get_sub_resource_parent(struct wined3d_texture *texture, unsigned int sub_resource_idx)
3528 unsigned int sub_count = texture->level_count * texture->layer_count;
3530 TRACE("texture %p, sub_resource_idx %u.\n", texture, sub_resource_idx);
3532 if (sub_resource_idx >= sub_count)
3534 WARN("sub_resource_idx %u >= sub_count %u.\n", sub_resource_idx, sub_count);
3535 return NULL;
3538 return texture->sub_resources[sub_resource_idx].parent;
3541 void CDECL wined3d_texture_set_sub_resource_parent(struct wined3d_texture *texture,
3542 unsigned int sub_resource_idx, void *parent)
3544 unsigned int sub_count = texture->level_count * texture->layer_count;
3546 TRACE("texture %p, sub_resource_idx %u, parent %p.\n", texture, sub_resource_idx, parent);
3548 if (sub_resource_idx >= sub_count)
3550 WARN("sub_resource_idx %u >= sub_count %u.\n", sub_resource_idx, sub_count);
3551 return;
3554 texture->sub_resources[sub_resource_idx].parent = parent;
3557 HRESULT CDECL wined3d_texture_get_sub_resource_desc(const struct wined3d_texture *texture,
3558 unsigned int sub_resource_idx, struct wined3d_sub_resource_desc *desc)
3560 unsigned int sub_count = texture->level_count * texture->layer_count;
3561 const struct wined3d_resource *resource;
3562 unsigned int level_idx;
3564 TRACE("texture %p, sub_resource_idx %u, desc %p.\n", texture, sub_resource_idx, desc);
3566 if (sub_resource_idx >= sub_count)
3568 WARN("sub_resource_idx %u >= sub_count %u.\n", sub_resource_idx, sub_count);
3569 return WINED3DERR_INVALIDCALL;
3572 resource = &texture->resource;
3573 desc->format = resource->format->id;
3574 desc->multisample_type = resource->multisample_type;
3575 desc->multisample_quality = resource->multisample_quality;
3576 desc->usage = resource->usage;
3577 desc->bind_flags = resource->bind_flags;
3578 desc->access = resource->access;
3580 level_idx = sub_resource_idx % texture->level_count;
3581 desc->width = wined3d_texture_get_level_width(texture, level_idx);
3582 desc->height = wined3d_texture_get_level_height(texture, level_idx);
3583 desc->depth = wined3d_texture_get_level_depth(texture, level_idx);
3584 desc->size = texture->sub_resources[sub_resource_idx].size;
3586 return WINED3D_OK;
3589 HRESULT wined3d_texture_gl_init(struct wined3d_texture_gl *texture_gl, struct wined3d_device *device,
3590 const struct wined3d_resource_desc *desc, unsigned int layer_count, unsigned int level_count,
3591 uint32_t flags, void *parent, const struct wined3d_parent_ops *parent_ops)
3593 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
3594 HRESULT hr;
3596 TRACE("texture_gl %p, device %p, desc %p, layer_count %u, "
3597 "level_count %u, flags %#x, parent %p, parent_ops %p.\n",
3598 texture_gl, device, desc, layer_count,
3599 level_count, flags, parent, parent_ops);
3601 if (!(desc->usage & WINED3DUSAGE_LEGACY_CUBEMAP) && layer_count > 1
3602 && !gl_info->supported[EXT_TEXTURE_ARRAY])
3604 WARN("OpenGL implementation does not support array textures.\n");
3605 return WINED3DERR_INVALIDCALL;
3608 switch (desc->resource_type)
3610 case WINED3D_RTYPE_TEXTURE_1D:
3611 if (layer_count > 1)
3612 texture_gl->target = GL_TEXTURE_1D_ARRAY;
3613 else
3614 texture_gl->target = GL_TEXTURE_1D;
3615 break;
3617 case WINED3D_RTYPE_TEXTURE_2D:
3618 if (desc->usage & WINED3DUSAGE_LEGACY_CUBEMAP)
3620 texture_gl->target = GL_TEXTURE_CUBE_MAP_ARB;
3622 else if (desc->multisample_type && gl_info->supported[ARB_TEXTURE_MULTISAMPLE])
3624 if (layer_count > 1)
3625 texture_gl->target = GL_TEXTURE_2D_MULTISAMPLE_ARRAY;
3626 else
3627 texture_gl->target = GL_TEXTURE_2D_MULTISAMPLE;
3629 else
3631 if (layer_count > 1)
3632 texture_gl->target = GL_TEXTURE_2D_ARRAY;
3633 else
3634 texture_gl->target = GL_TEXTURE_2D;
3636 break;
3638 case WINED3D_RTYPE_TEXTURE_3D:
3639 if (!gl_info->supported[EXT_TEXTURE3D])
3641 WARN("OpenGL implementation does not support 3D textures.\n");
3642 return WINED3DERR_INVALIDCALL;
3644 texture_gl->target = GL_TEXTURE_3D;
3645 break;
3647 default:
3648 ERR("Invalid resource type %s.\n", debug_d3dresourcetype(desc->resource_type));
3649 return WINED3DERR_INVALIDCALL;
3652 list_init(&texture_gl->renderbuffers);
3654 if (FAILED(hr = wined3d_texture_init(&texture_gl->t, desc, layer_count, level_count,
3655 flags, device, parent, parent_ops, &texture_gl[1], &texture_gl_ops)))
3656 return hr;
3658 if (texture_gl->t.resource.gl_type == WINED3D_GL_RES_TYPE_TEX_RECT)
3659 texture_gl->target = GL_TEXTURE_RECTANGLE_ARB;
3661 return WINED3D_OK;
3664 HRESULT CDECL wined3d_texture_create(struct wined3d_device *device, const struct wined3d_resource_desc *desc,
3665 UINT layer_count, UINT level_count, DWORD flags, const struct wined3d_sub_resource_data *data,
3666 void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_texture **texture)
3668 unsigned int sub_count = level_count * layer_count;
3669 unsigned int i;
3670 HRESULT hr;
3672 TRACE("device %p, desc %p, layer_count %u, level_count %u, flags %#x, data %p, "
3673 "parent %p, parent_ops %p, texture %p.\n",
3674 device, desc, layer_count, level_count, flags, data, parent, parent_ops, texture);
3676 if (!layer_count)
3678 WARN("Invalid layer count.\n");
3679 return E_INVALIDARG;
3681 if ((desc->usage & WINED3DUSAGE_LEGACY_CUBEMAP) && layer_count != 6)
3683 ERR("Invalid layer count %u for legacy cubemap.\n", layer_count);
3684 layer_count = 6;
3687 if (!level_count)
3689 WARN("Invalid level count.\n");
3690 return WINED3DERR_INVALIDCALL;
3693 if (desc->multisample_type != WINED3D_MULTISAMPLE_NONE)
3695 const struct wined3d_format *format = wined3d_get_format(device->adapter, desc->format, desc->bind_flags);
3697 if (desc->multisample_type == WINED3D_MULTISAMPLE_NON_MASKABLE
3698 && desc->multisample_quality >= wined3d_popcount(format->multisample_types))
3700 WARN("Unsupported quality level %u requested for WINED3D_MULTISAMPLE_NON_MASKABLE.\n",
3701 desc->multisample_quality);
3702 return WINED3DERR_NOTAVAILABLE;
3704 if (desc->multisample_type != WINED3D_MULTISAMPLE_NON_MASKABLE
3705 && (!(format->multisample_types & 1u << (desc->multisample_type - 1))
3706 || (desc->multisample_quality && desc->multisample_quality != WINED3D_STANDARD_MULTISAMPLE_PATTERN)))
3708 WARN("Unsupported multisample type %u quality %u requested.\n", desc->multisample_type,
3709 desc->multisample_quality);
3710 return WINED3DERR_NOTAVAILABLE;
3714 if (data)
3716 for (i = 0; i < sub_count; ++i)
3718 if (data[i].data)
3719 continue;
3721 WARN("Invalid sub-resource data specified for sub-resource %u.\n", i);
3722 return E_INVALIDARG;
3726 if (FAILED(hr = device->adapter->adapter_ops->adapter_create_texture(device, desc,
3727 layer_count, level_count, flags, parent, parent_ops, texture)))
3728 return hr;
3730 /* FIXME: We'd like to avoid ever allocating system memory for the texture
3731 * in this case. */
3732 if (data)
3734 struct wined3d_box box;
3736 for (i = 0; i < sub_count; ++i)
3738 wined3d_texture_get_level_box(*texture, i % (*texture)->level_count, &box);
3739 wined3d_cs_emit_update_sub_resource(device->cs, &(*texture)->resource,
3740 i, &box, data[i].data, data[i].row_pitch, data[i].slice_pitch);
3744 TRACE("Created texture %p.\n", *texture);
3746 return WINED3D_OK;
3749 HRESULT CDECL wined3d_texture_get_dc(struct wined3d_texture *texture, unsigned int sub_resource_idx, HDC *dc)
3751 struct wined3d_device *device = texture->resource.device;
3752 struct wined3d_texture_sub_resource *sub_resource;
3753 struct wined3d_dc_info *dc_info;
3755 TRACE("texture %p, sub_resource_idx %u, dc %p.\n", texture, sub_resource_idx, dc);
3757 if (!(texture->flags & WINED3D_TEXTURE_GET_DC))
3759 WARN("Texture does not support GetDC\n");
3760 /* Don't touch the DC */
3761 return WINED3DERR_INVALIDCALL;
3764 if (!(sub_resource = wined3d_texture_get_sub_resource(texture, sub_resource_idx)))
3765 return WINED3DERR_INVALIDCALL;
3767 if (texture->resource.type != WINED3D_RTYPE_TEXTURE_2D)
3769 WARN("Not supported on %s resources.\n", debug_d3dresourcetype(texture->resource.type));
3770 return WINED3DERR_INVALIDCALL;
3773 if (texture->resource.map_count && !(texture->flags & WINED3D_TEXTURE_GET_DC_LENIENT))
3774 return WINED3DERR_INVALIDCALL;
3776 if (!(dc_info = texture->dc_info) || !dc_info[sub_resource_idx].dc)
3778 struct wined3d_texture_idx texture_idx = {texture, sub_resource_idx};
3780 wined3d_cs_init_object(device->cs, wined3d_texture_create_dc, &texture_idx);
3781 wined3d_cs_finish(device->cs, WINED3D_CS_QUEUE_DEFAULT);
3782 if (!(dc_info = texture->dc_info) || !dc_info[sub_resource_idx].dc)
3783 return WINED3DERR_INVALIDCALL;
3786 if (!(texture->flags & WINED3D_TEXTURE_GET_DC_LENIENT))
3787 texture->flags |= WINED3D_TEXTURE_DC_IN_USE;
3788 ++texture->resource.map_count;
3789 ++sub_resource->map_count;
3791 *dc = dc_info[sub_resource_idx].dc;
3792 TRACE("Returning dc %p.\n", *dc);
3794 return WINED3D_OK;
3797 HRESULT CDECL wined3d_texture_release_dc(struct wined3d_texture *texture, unsigned int sub_resource_idx, HDC dc)
3799 struct wined3d_device *device = texture->resource.device;
3800 struct wined3d_texture_sub_resource *sub_resource;
3801 struct wined3d_dc_info *dc_info;
3803 TRACE("texture %p, sub_resource_idx %u, dc %p.\n", texture, sub_resource_idx, dc);
3805 if (!(sub_resource = wined3d_texture_get_sub_resource(texture, sub_resource_idx)))
3806 return WINED3DERR_INVALIDCALL;
3808 if (texture->resource.type != WINED3D_RTYPE_TEXTURE_2D)
3810 WARN("Not supported on %s resources.\n", debug_d3dresourcetype(texture->resource.type));
3811 return WINED3DERR_INVALIDCALL;
3814 if (!(texture->flags & (WINED3D_TEXTURE_GET_DC_LENIENT | WINED3D_TEXTURE_DC_IN_USE)))
3815 return WINED3DERR_INVALIDCALL;
3817 if (!(dc_info = texture->dc_info) || dc_info[sub_resource_idx].dc != dc)
3819 WARN("Application tries to release invalid DC %p, sub-resource DC is %p.\n",
3820 dc, dc_info ? dc_info[sub_resource_idx].dc : NULL);
3821 return WINED3DERR_INVALIDCALL;
3824 if (!(texture->resource.usage & WINED3DUSAGE_OWNDC))
3826 struct wined3d_texture_idx texture_idx = {texture, sub_resource_idx};
3828 wined3d_cs_destroy_object(device->cs, wined3d_texture_destroy_dc, &texture_idx);
3829 wined3d_cs_finish(device->cs, WINED3D_CS_QUEUE_DEFAULT);
3832 --sub_resource->map_count;
3833 if (!--texture->resource.map_count && texture->update_map_binding)
3834 wined3d_texture_update_map_binding(texture);
3835 if (!(texture->flags & WINED3D_TEXTURE_GET_DC_LENIENT))
3836 texture->flags &= ~WINED3D_TEXTURE_DC_IN_USE;
3838 return WINED3D_OK;
3841 void wined3d_texture_upload_from_texture(struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx,
3842 unsigned int dst_x, unsigned int dst_y, unsigned int dst_z, struct wined3d_texture *src_texture,
3843 unsigned int src_sub_resource_idx, const struct wined3d_box *src_box)
3845 unsigned int src_row_pitch, src_slice_pitch;
3846 unsigned int update_w, update_h, update_d;
3847 unsigned int src_level, dst_level;
3848 struct wined3d_context *context;
3849 struct wined3d_bo_address data;
3851 TRACE("dst_texture %p, dst_sub_resource_idx %u, dst_x %u, dst_y %u, dst_z %u, "
3852 "src_texture %p, src_sub_resource_idx %u, src_box %s.\n",
3853 dst_texture, dst_sub_resource_idx, dst_x, dst_y, dst_z,
3854 src_texture, src_sub_resource_idx, debug_box(src_box));
3856 context = context_acquire(dst_texture->resource.device, NULL, 0);
3858 /* Only load the sub-resource for partial updates. For newly allocated
3859 * textures the texture wouldn't be the current location, and we'd upload
3860 * zeroes just to overwrite them again. */
3861 update_w = src_box->right - src_box->left;
3862 update_h = src_box->bottom - src_box->top;
3863 update_d = src_box->back - src_box->front;
3864 dst_level = dst_sub_resource_idx % dst_texture->level_count;
3865 if (update_w == wined3d_texture_get_level_width(dst_texture, dst_level)
3866 && update_h == wined3d_texture_get_level_height(dst_texture, dst_level)
3867 && update_d == wined3d_texture_get_level_depth(dst_texture, dst_level))
3868 wined3d_texture_prepare_location(dst_texture, dst_sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB);
3869 else
3870 wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB);
3872 src_level = src_sub_resource_idx % src_texture->level_count;
3873 wined3d_texture_get_memory(src_texture, src_sub_resource_idx, &data,
3874 src_texture->sub_resources[src_sub_resource_idx].locations);
3875 wined3d_texture_get_pitch(src_texture, src_level, &src_row_pitch, &src_slice_pitch);
3877 dst_texture->texture_ops->texture_upload_data(context, wined3d_const_bo_address(&data),
3878 src_texture->resource.format, src_box, src_row_pitch, src_slice_pitch, dst_texture,
3879 dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB, dst_x, dst_y, dst_z);
3881 context_release(context);
3883 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB);
3884 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB);
3887 /* Partial downloads are not supported. */
3888 void wined3d_texture_download_from_texture(struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx,
3889 struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx)
3891 unsigned int src_level, dst_level, dst_row_pitch, dst_slice_pitch;
3892 unsigned int dst_location = dst_texture->resource.map_binding;
3893 struct wined3d_context *context;
3894 struct wined3d_bo_address data;
3895 struct wined3d_box src_box;
3896 unsigned int src_location;
3898 context = context_acquire(src_texture->resource.device, NULL, 0);
3900 wined3d_texture_prepare_location(dst_texture, dst_sub_resource_idx, context, dst_location);
3901 wined3d_texture_get_memory(dst_texture, dst_sub_resource_idx, &data, dst_location);
3903 if (src_texture->sub_resources[src_sub_resource_idx].locations & WINED3D_LOCATION_TEXTURE_RGB)
3904 src_location = WINED3D_LOCATION_TEXTURE_RGB;
3905 else
3906 src_location = WINED3D_LOCATION_TEXTURE_SRGB;
3907 src_level = src_sub_resource_idx % src_texture->level_count;
3908 wined3d_texture_get_level_box(src_texture, src_level, &src_box);
3910 dst_level = dst_sub_resource_idx % dst_texture->level_count;
3911 wined3d_texture_get_pitch(dst_texture, dst_level, &dst_row_pitch, &dst_slice_pitch);
3913 src_texture->texture_ops->texture_download_data(context, src_texture, src_sub_resource_idx, src_location,
3914 &src_box, &data, dst_texture->resource.format, 0, 0, 0, dst_row_pitch, dst_slice_pitch);
3916 context_release(context);
3918 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, dst_location);
3919 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~dst_location);
3922 static void wined3d_texture_no3d_upload_data(struct wined3d_context *context,
3923 const struct wined3d_const_bo_address *src_bo_addr, const struct wined3d_format *src_format,
3924 const struct wined3d_box *src_box, unsigned int src_row_pitch, unsigned int src_slice_pitch,
3925 struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, unsigned int dst_location,
3926 unsigned int dst_x, unsigned int dst_y, unsigned int dst_z)
3928 FIXME("Not implemented.\n");
3931 static void wined3d_texture_no3d_download_data(struct wined3d_context *context,
3932 struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx, unsigned int src_location,
3933 const struct wined3d_box *src_box, const struct wined3d_bo_address *dst_bo_addr,
3934 const struct wined3d_format *dst_format, unsigned int dst_x, unsigned int dst_y, unsigned int dst_z,
3935 unsigned int dst_row_pitch, unsigned int dst_slice_pitch)
3937 FIXME("Not implemented.\n");
3940 static BOOL wined3d_texture_no3d_prepare_location(struct wined3d_texture *texture,
3941 unsigned int sub_resource_idx, struct wined3d_context *context, unsigned int location)
3943 switch (location)
3945 case WINED3D_LOCATION_SYSMEM:
3946 return wined3d_resource_prepare_sysmem(&texture->resource);
3948 case WINED3D_LOCATION_USER_MEMORY:
3949 if (!texture->user_memory)
3950 ERR("Preparing WINED3D_LOCATION_USER_MEMORY, but texture->user_memory is NULL.\n");
3951 return TRUE;
3953 default:
3954 FIXME("Unhandled location %s.\n", wined3d_debug_location(location));
3955 return FALSE;
3959 static BOOL wined3d_texture_no3d_load_location(struct wined3d_texture *texture,
3960 unsigned int sub_resource_idx, struct wined3d_context *context, DWORD location)
3962 TRACE("texture %p, sub_resource_idx %u, context %p, location %s.\n",
3963 texture, sub_resource_idx, context, wined3d_debug_location(location));
3965 if (location == WINED3D_LOCATION_USER_MEMORY || location == WINED3D_LOCATION_SYSMEM)
3966 return TRUE;
3968 ERR("Unhandled location %s.\n", wined3d_debug_location(location));
3970 return FALSE;
3973 static const struct wined3d_texture_ops wined3d_texture_no3d_ops =
3975 wined3d_texture_no3d_prepare_location,
3976 wined3d_texture_no3d_load_location,
3977 wined3d_texture_no3d_upload_data,
3978 wined3d_texture_no3d_download_data,
3981 HRESULT wined3d_texture_no3d_init(struct wined3d_texture *texture_no3d, struct wined3d_device *device,
3982 const struct wined3d_resource_desc *desc, unsigned int layer_count, unsigned int level_count,
3983 uint32_t flags, void *parent, const struct wined3d_parent_ops *parent_ops)
3985 TRACE("texture_no3d %p, device %p, desc %p, layer_count %u, "
3986 "level_count %u, flags %#x, parent %p, parent_ops %p.\n",
3987 texture_no3d, device, desc, layer_count,
3988 level_count, flags, parent, parent_ops);
3990 return wined3d_texture_init(texture_no3d, desc, layer_count, level_count,
3991 flags, device, parent, parent_ops, &texture_no3d[1], &wined3d_texture_no3d_ops);
3994 static void wined3d_texture_vk_upload_data(struct wined3d_context *context,
3995 const struct wined3d_const_bo_address *src_bo_addr, const struct wined3d_format *src_format,
3996 const struct wined3d_box *src_box, unsigned int src_row_pitch, unsigned int src_slice_pitch,
3997 struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, unsigned int dst_location,
3998 unsigned int dst_x, unsigned int dst_y, unsigned int dst_z)
4000 FIXME("Not implemented.\n");
4003 static void wined3d_texture_vk_download_data(struct wined3d_context *context,
4004 struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx, unsigned int src_location,
4005 const struct wined3d_box *src_box, const struct wined3d_bo_address *dst_bo_addr,
4006 const struct wined3d_format *dst_format, unsigned int dst_x, unsigned int dst_y, unsigned int dst_z,
4007 unsigned int dst_row_pitch, unsigned int dst_slice_pitch)
4009 FIXME("Not implemented.\n");
4012 static BOOL wined3d_texture_vk_prepare_location(struct wined3d_texture *texture,
4013 unsigned int sub_resource_idx, struct wined3d_context *context, unsigned int location)
4015 switch (location)
4017 case WINED3D_LOCATION_SYSMEM:
4018 return wined3d_resource_prepare_sysmem(&texture->resource);
4020 case WINED3D_LOCATION_USER_MEMORY:
4021 if (!texture->user_memory)
4022 ERR("Preparing WINED3D_LOCATION_USER_MEMORY, but texture->user_memory is NULL.\n");
4023 return TRUE;
4025 case WINED3D_LOCATION_TEXTURE_RGB:
4026 /* The Vulkan image is created during resource creation. */
4027 return TRUE;
4029 default:
4030 FIXME("Unhandled location %s.\n", wined3d_debug_location(location));
4031 return FALSE;
4035 static BOOL wined3d_texture_vk_load_location(struct wined3d_texture *texture,
4036 unsigned int sub_resource_idx, struct wined3d_context *context, DWORD location)
4038 FIXME("Not implemented.\n");
4040 return FALSE;
4043 static const struct wined3d_texture_ops wined3d_texture_vk_ops =
4045 wined3d_texture_vk_prepare_location,
4046 wined3d_texture_vk_load_location,
4047 wined3d_texture_vk_upload_data,
4048 wined3d_texture_vk_download_data,
4051 HRESULT wined3d_texture_vk_init(struct wined3d_texture_vk *texture_vk, struct wined3d_device *device,
4052 const struct wined3d_resource_desc *desc, unsigned int layer_count, unsigned int level_count,
4053 uint32_t flags, void *parent, const struct wined3d_parent_ops *parent_ops)
4055 TRACE("texture_vk %p, device %p, desc %p, layer_count %u, "
4056 "level_count %u, flags %#x, parent %p, parent_ops %p.\n",
4057 texture_vk, device, desc, layer_count,
4058 level_count, flags, parent, parent_ops);
4060 return wined3d_texture_init(&texture_vk->t, desc, layer_count, level_count,
4061 flags, device, parent, parent_ops, &texture_vk[1], &wined3d_texture_vk_ops);