wined3d: Move OpenGL initialisation code to adapter_gl.c.
[wine.git] / dlls / wined3d / texture.c
blob4947a5618d674673ec47fa2591b838ee5caf3100
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 struct wined3d_texture_idx
35 struct wined3d_texture *texture;
36 unsigned int sub_resource_idx;
39 struct wined3d_rect_f
41 float l;
42 float t;
43 float r;
44 float b;
47 static BOOL wined3d_texture_use_pbo(const struct wined3d_texture *texture, const struct wined3d_gl_info *gl_info)
49 return !(texture->resource.access & WINED3D_RESOURCE_ACCESS_CPU)
50 && texture->resource.usage & WINED3DUSAGE_DYNAMIC
51 && gl_info->supported[ARB_PIXEL_BUFFER_OBJECT]
52 && !texture->resource.format->conv_byte_count
53 && !(texture->flags & (WINED3D_TEXTURE_PIN_SYSMEM | WINED3D_TEXTURE_COND_NP2_EMULATED));
56 static BOOL wined3d_texture_use_immutable_storage(const struct wined3d_texture *texture,
57 const struct wined3d_gl_info *gl_info)
59 /* We don't expect to create texture views for textures with height-scaled formats.
60 * Besides, ARB_texture_storage doesn't allow specifying exact sizes for all levels. */
61 return gl_info->supported[ARB_TEXTURE_STORAGE]
62 && !(texture->resource.format_flags & WINED3DFMT_FLAG_HEIGHT_SCALE);
65 /* Front buffer coordinates are always full screen coordinates, but our GL
66 * drawable is limited to the window's client area. The sysmem and texture
67 * copies do have the full screen size. Note that GL has a bottom-left
68 * origin, while D3D has a top-left origin. */
69 void wined3d_texture_translate_drawable_coords(const struct wined3d_texture *texture, HWND window, RECT *rect)
71 unsigned int drawable_height;
72 POINT offset = {0, 0};
73 RECT windowsize;
75 if (!texture->swapchain)
76 return;
78 if (texture == texture->swapchain->front_buffer)
80 ScreenToClient(window, &offset);
81 OffsetRect(rect, offset.x, offset.y);
84 GetClientRect(window, &windowsize);
85 drawable_height = windowsize.bottom - windowsize.top;
87 rect->top = drawable_height - rect->top;
88 rect->bottom = drawable_height - rect->bottom;
91 GLenum wined3d_texture_get_gl_buffer(const struct wined3d_texture *texture)
93 const struct wined3d_swapchain *swapchain = texture->swapchain;
95 TRACE("texture %p.\n", texture);
97 if (!swapchain)
99 ERR("Texture %p is not part of a swapchain.\n", texture);
100 return GL_NONE;
103 if (texture == swapchain->front_buffer)
105 TRACE("Returning GL_FRONT.\n");
106 return GL_FRONT;
109 if (texture == swapchain->back_buffers[0])
111 TRACE("Returning GL_BACK.\n");
112 return GL_BACK;
115 FIXME("Higher back buffer, returning GL_BACK.\n");
116 return GL_BACK;
119 static DWORD wined3d_resource_access_from_location(DWORD location)
121 switch (location)
123 case WINED3D_LOCATION_DISCARDED:
124 return 0;
126 case WINED3D_LOCATION_SYSMEM:
127 case WINED3D_LOCATION_USER_MEMORY:
128 return WINED3D_RESOURCE_ACCESS_CPU;
130 case WINED3D_LOCATION_BUFFER:
131 case WINED3D_LOCATION_DRAWABLE:
132 case WINED3D_LOCATION_TEXTURE_RGB:
133 case WINED3D_LOCATION_TEXTURE_SRGB:
134 case WINED3D_LOCATION_RB_MULTISAMPLE:
135 case WINED3D_LOCATION_RB_RESOLVED:
136 return WINED3D_RESOURCE_ACCESS_GPU;
138 default:
139 FIXME("Unhandled location %#x.\n", location);
140 return 0;
144 static inline void cube_coords_float(const RECT *r, UINT w, UINT h, struct wined3d_rect_f *f)
146 f->l = ((r->left * 2.0f) / w) - 1.0f;
147 f->t = ((r->top * 2.0f) / h) - 1.0f;
148 f->r = ((r->right * 2.0f) / w) - 1.0f;
149 f->b = ((r->bottom * 2.0f) / h) - 1.0f;
152 void texture2d_get_blt_info(const struct wined3d_texture *texture,
153 unsigned int sub_resource_idx, const RECT *rect, struct wined3d_blt_info *info)
155 struct wined3d_vec3 *coords = info->texcoords;
156 struct wined3d_rect_f f;
157 unsigned int level;
158 GLenum target;
159 GLsizei w, h;
161 level = sub_resource_idx % texture->level_count;
162 w = wined3d_texture_get_level_pow2_width(texture, level);
163 h = wined3d_texture_get_level_pow2_height(texture, level);
164 target = wined3d_texture_get_sub_resource_target(texture, sub_resource_idx);
166 switch (target)
168 default:
169 FIXME("Unsupported texture target %#x.\n", target);
170 /* Fall back to GL_TEXTURE_2D */
171 case GL_TEXTURE_2D:
172 info->bind_target = GL_TEXTURE_2D;
173 coords[0].x = (float)rect->left / w;
174 coords[0].y = (float)rect->top / h;
175 coords[0].z = 0.0f;
177 coords[1].x = (float)rect->right / w;
178 coords[1].y = (float)rect->top / h;
179 coords[1].z = 0.0f;
181 coords[2].x = (float)rect->left / w;
182 coords[2].y = (float)rect->bottom / h;
183 coords[2].z = 0.0f;
185 coords[3].x = (float)rect->right / w;
186 coords[3].y = (float)rect->bottom / h;
187 coords[3].z = 0.0f;
188 break;
190 case GL_TEXTURE_RECTANGLE_ARB:
191 info->bind_target = GL_TEXTURE_RECTANGLE_ARB;
192 coords[0].x = rect->left; coords[0].y = rect->top; coords[0].z = 0.0f;
193 coords[1].x = rect->right; coords[1].y = rect->top; coords[1].z = 0.0f;
194 coords[2].x = rect->left; coords[2].y = rect->bottom; coords[2].z = 0.0f;
195 coords[3].x = rect->right; coords[3].y = rect->bottom; coords[3].z = 0.0f;
196 break;
198 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
199 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
200 cube_coords_float(rect, w, h, &f);
202 coords[0].x = 1.0f; coords[0].y = -f.t; coords[0].z = -f.l;
203 coords[1].x = 1.0f; coords[1].y = -f.t; coords[1].z = -f.r;
204 coords[2].x = 1.0f; coords[2].y = -f.b; coords[2].z = -f.l;
205 coords[3].x = 1.0f; coords[3].y = -f.b; coords[3].z = -f.r;
206 break;
208 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
209 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
210 cube_coords_float(rect, w, h, &f);
212 coords[0].x = -1.0f; coords[0].y = -f.t; coords[0].z = f.l;
213 coords[1].x = -1.0f; coords[1].y = -f.t; coords[1].z = f.r;
214 coords[2].x = -1.0f; coords[2].y = -f.b; coords[2].z = f.l;
215 coords[3].x = -1.0f; coords[3].y = -f.b; coords[3].z = f.r;
216 break;
218 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
219 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
220 cube_coords_float(rect, w, h, &f);
222 coords[0].x = f.l; coords[0].y = 1.0f; coords[0].z = f.t;
223 coords[1].x = f.r; coords[1].y = 1.0f; coords[1].z = f.t;
224 coords[2].x = f.l; coords[2].y = 1.0f; coords[2].z = f.b;
225 coords[3].x = f.r; coords[3].y = 1.0f; coords[3].z = f.b;
226 break;
228 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
229 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
230 cube_coords_float(rect, w, h, &f);
232 coords[0].x = f.l; coords[0].y = -1.0f; coords[0].z = -f.t;
233 coords[1].x = f.r; coords[1].y = -1.0f; coords[1].z = -f.t;
234 coords[2].x = f.l; coords[2].y = -1.0f; coords[2].z = -f.b;
235 coords[3].x = f.r; coords[3].y = -1.0f; coords[3].z = -f.b;
236 break;
238 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
239 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
240 cube_coords_float(rect, w, h, &f);
242 coords[0].x = f.l; coords[0].y = -f.t; coords[0].z = 1.0f;
243 coords[1].x = f.r; coords[1].y = -f.t; coords[1].z = 1.0f;
244 coords[2].x = f.l; coords[2].y = -f.b; coords[2].z = 1.0f;
245 coords[3].x = f.r; coords[3].y = -f.b; coords[3].z = 1.0f;
246 break;
248 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
249 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
250 cube_coords_float(rect, w, h, &f);
252 coords[0].x = -f.l; coords[0].y = -f.t; coords[0].z = -1.0f;
253 coords[1].x = -f.r; coords[1].y = -f.t; coords[1].z = -1.0f;
254 coords[2].x = -f.l; coords[2].y = -f.b; coords[2].z = -1.0f;
255 coords[3].x = -f.r; coords[3].y = -f.b; coords[3].z = -1.0f;
256 break;
260 static void wined3d_texture_evict_sysmem(struct wined3d_texture *texture)
262 struct wined3d_texture_sub_resource *sub_resource;
263 unsigned int i, sub_count;
265 if (texture->flags & (WINED3D_TEXTURE_CONVERTED | WINED3D_TEXTURE_PIN_SYSMEM)
266 || texture->download_count > WINED3D_TEXTURE_DYNAMIC_MAP_THRESHOLD)
268 TRACE("Not evicting system memory for texture %p.\n", texture);
269 return;
272 TRACE("Evicting system memory for texture %p.\n", texture);
274 sub_count = texture->level_count * texture->layer_count;
275 for (i = 0; i < sub_count; ++i)
277 sub_resource = &texture->sub_resources[i];
278 if (sub_resource->locations == WINED3D_LOCATION_SYSMEM)
279 ERR("WINED3D_LOCATION_SYSMEM is the only location for sub-resource %u of texture %p.\n",
280 i, texture);
281 sub_resource->locations &= ~WINED3D_LOCATION_SYSMEM;
283 wined3d_resource_free_sysmem(&texture->resource);
286 void wined3d_texture_validate_location(struct wined3d_texture *texture,
287 unsigned int sub_resource_idx, DWORD location)
289 struct wined3d_texture_sub_resource *sub_resource;
290 DWORD previous_locations;
292 TRACE("texture %p, sub_resource_idx %u, location %s.\n",
293 texture, sub_resource_idx, wined3d_debug_location(location));
295 sub_resource = &texture->sub_resources[sub_resource_idx];
296 previous_locations = sub_resource->locations;
297 sub_resource->locations |= location;
298 if (previous_locations == WINED3D_LOCATION_SYSMEM && location != WINED3D_LOCATION_SYSMEM
299 && !--texture->sysmem_count)
300 wined3d_texture_evict_sysmem(texture);
302 TRACE("New locations flags are %s.\n", wined3d_debug_location(sub_resource->locations));
305 static void wined3d_texture_set_dirty(struct wined3d_texture *texture)
307 texture->flags &= ~(WINED3D_TEXTURE_RGB_VALID | WINED3D_TEXTURE_SRGB_VALID);
310 void wined3d_texture_invalidate_location(struct wined3d_texture *texture,
311 unsigned int sub_resource_idx, DWORD location)
313 struct wined3d_texture_sub_resource *sub_resource;
314 DWORD previous_locations;
316 TRACE("texture %p, sub_resource_idx %u, location %s.\n",
317 texture, sub_resource_idx, wined3d_debug_location(location));
319 if (location & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB))
320 wined3d_texture_set_dirty(texture);
322 sub_resource = &texture->sub_resources[sub_resource_idx];
323 previous_locations = sub_resource->locations;
324 sub_resource->locations &= ~location;
325 if (previous_locations != WINED3D_LOCATION_SYSMEM && sub_resource->locations == WINED3D_LOCATION_SYSMEM)
326 ++texture->sysmem_count;
328 TRACE("New locations flags are %s.\n", wined3d_debug_location(sub_resource->locations));
330 if (!sub_resource->locations)
331 ERR("Sub-resource %u of texture %p does not have any up to date location.\n",
332 sub_resource_idx, texture);
335 static BOOL wined3d_texture_copy_sysmem_location(struct wined3d_texture *texture,
336 unsigned int sub_resource_idx, struct wined3d_context *context, DWORD location)
338 unsigned int size = texture->sub_resources[sub_resource_idx].size;
339 struct wined3d_device *device = texture->resource.device;
340 const struct wined3d_gl_info *gl_info;
341 struct wined3d_bo_address dst, src;
343 if (!wined3d_texture_prepare_location(texture, sub_resource_idx, context, location))
344 return FALSE;
346 wined3d_texture_get_memory(texture, sub_resource_idx, &dst, location);
347 wined3d_texture_get_memory(texture, sub_resource_idx, &src,
348 texture->sub_resources[sub_resource_idx].locations);
350 if (dst.buffer_object)
352 context = context_acquire(device, NULL, 0);
353 gl_info = context->gl_info;
354 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, dst.buffer_object));
355 GL_EXTCALL(glBufferSubData(GL_PIXEL_UNPACK_BUFFER, 0, size, src.addr));
356 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));
357 checkGLcall("PBO upload");
358 context_release(context);
359 return TRUE;
362 if (src.buffer_object)
364 context = context_acquire(device, NULL, 0);
365 gl_info = context->gl_info;
366 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, src.buffer_object));
367 GL_EXTCALL(glGetBufferSubData(GL_PIXEL_PACK_BUFFER, 0, size, dst.addr));
368 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
369 checkGLcall("PBO download");
370 context_release(context);
371 return TRUE;
374 memcpy(dst.addr, src.addr, size);
375 return TRUE;
378 /* Context activation is done by the caller. Context may be NULL in
379 * WINED3D_NO3D mode. */
380 BOOL wined3d_texture_load_location(struct wined3d_texture *texture,
381 unsigned int sub_resource_idx, struct wined3d_context *context, DWORD location)
383 static const DWORD sysmem_locations = WINED3D_LOCATION_SYSMEM | WINED3D_LOCATION_USER_MEMORY
384 | WINED3D_LOCATION_BUFFER;
385 DWORD current = texture->sub_resources[sub_resource_idx].locations;
386 BOOL ret;
388 TRACE("texture %p, sub_resource_idx %u, context %p, location %s.\n",
389 texture, sub_resource_idx, context, wined3d_debug_location(location));
391 TRACE("Current resource location %s.\n", wined3d_debug_location(current));
393 if (current & location)
395 TRACE("Location %s is already up to date.\n", wined3d_debug_location(location));
396 return TRUE;
399 if (WARN_ON(d3d))
401 DWORD required_access = wined3d_resource_access_from_location(location);
402 if ((texture->resource.access & required_access) != required_access)
403 WARN("Operation requires %#x access, but texture only has %#x.\n",
404 required_access, texture->resource.access);
407 if (current & WINED3D_LOCATION_DISCARDED)
409 TRACE("Sub-resource previously discarded, nothing to do.\n");
410 if (!wined3d_texture_prepare_location(texture, sub_resource_idx, context, location))
411 return FALSE;
412 wined3d_texture_validate_location(texture, sub_resource_idx, location);
413 wined3d_texture_invalidate_location(texture, sub_resource_idx, WINED3D_LOCATION_DISCARDED);
414 return TRUE;
417 if (!current)
419 ERR("Sub-resource %u of texture %p does not have any up to date location.\n",
420 sub_resource_idx, texture);
421 wined3d_texture_validate_location(texture, sub_resource_idx, WINED3D_LOCATION_DISCARDED);
422 return wined3d_texture_load_location(texture, sub_resource_idx, context, location);
425 if ((location & sysmem_locations) && (current & sysmem_locations))
426 ret = wined3d_texture_copy_sysmem_location(texture, sub_resource_idx, context, location);
427 else
428 ret = texture->texture_ops->texture_load_location(texture, sub_resource_idx, context, location);
430 if (ret)
431 wined3d_texture_validate_location(texture, sub_resource_idx, location);
433 return ret;
436 void wined3d_texture_get_memory(struct wined3d_texture *texture, unsigned int sub_resource_idx,
437 struct wined3d_bo_address *data, DWORD locations)
439 struct wined3d_texture_sub_resource *sub_resource;
441 TRACE("texture %p, sub_resource_idx %u, data %p, locations %s.\n",
442 texture, sub_resource_idx, data, wined3d_debug_location(locations));
444 sub_resource = &texture->sub_resources[sub_resource_idx];
445 if (locations & WINED3D_LOCATION_BUFFER)
447 data->addr = NULL;
448 data->buffer_object = sub_resource->buffer_object;
449 return;
451 if (locations & WINED3D_LOCATION_USER_MEMORY)
453 data->addr = texture->user_memory;
454 data->buffer_object = 0;
455 return;
457 if (locations & WINED3D_LOCATION_SYSMEM)
459 data->addr = texture->resource.heap_memory;
460 data->addr += sub_resource->offset;
461 data->buffer_object = 0;
462 return;
465 ERR("Unexpected locations %s.\n", wined3d_debug_location(locations));
466 data->addr = NULL;
467 data->buffer_object = 0;
470 /* Context activation is done by the caller. */
471 static void wined3d_texture_remove_buffer_object(struct wined3d_texture *texture,
472 unsigned int sub_resource_idx, const struct wined3d_gl_info *gl_info)
474 GLuint *buffer_object = &texture->sub_resources[sub_resource_idx].buffer_object;
476 GL_EXTCALL(glDeleteBuffers(1, buffer_object));
477 checkGLcall("glDeleteBuffers");
479 TRACE("Deleted buffer object %u for texture %p, sub-resource %u.\n",
480 *buffer_object, texture, sub_resource_idx);
482 wined3d_texture_invalidate_location(texture, sub_resource_idx, WINED3D_LOCATION_BUFFER);
483 *buffer_object = 0;
486 static void wined3d_texture_update_map_binding(struct wined3d_texture *texture)
488 unsigned int sub_count = texture->level_count * texture->layer_count;
489 const struct wined3d_device *device = texture->resource.device;
490 DWORD map_binding = texture->update_map_binding;
491 struct wined3d_context *context = NULL;
492 unsigned int i;
494 if (device->d3d_initialized)
495 context = context_acquire(device, NULL, 0);
497 for (i = 0; i < sub_count; ++i)
499 if (texture->sub_resources[i].locations == texture->resource.map_binding
500 && !wined3d_texture_load_location(texture, i, context, map_binding))
501 ERR("Failed to load location %s.\n", wined3d_debug_location(map_binding));
502 if (texture->resource.map_binding == WINED3D_LOCATION_BUFFER)
503 wined3d_texture_remove_buffer_object(texture, i, context->gl_info);
506 if (context)
507 context_release(context);
509 texture->resource.map_binding = map_binding;
510 texture->update_map_binding = 0;
513 void wined3d_texture_set_map_binding(struct wined3d_texture *texture, DWORD map_binding)
515 texture->update_map_binding = map_binding;
516 if (!texture->resource.map_count)
517 wined3d_texture_update_map_binding(texture);
520 /* A GL context is provided by the caller */
521 static void gltexture_delete(struct wined3d_device *device, const struct wined3d_gl_info *gl_info,
522 struct gl_texture *tex)
524 context_gl_resource_released(device, tex->name, FALSE);
525 gl_info->gl_ops.gl.p_glDeleteTextures(1, &tex->name);
526 tex->name = 0;
529 static unsigned int wined3d_texture_get_gl_sample_count(const struct wined3d_texture *texture)
531 const struct wined3d_format *format = texture->resource.format;
533 /* TODO: NVIDIA expose their Coverage Sample Anti-Aliasing (CSAA)
534 * feature through type == MULTISAMPLE_XX and quality != 0. This could
535 * be mapped to GL_NV_framebuffer_multisample_coverage.
537 * AMD have a similar feature called Enhanced Quality Anti-Aliasing
538 * (EQAA), but it does not have an equivalent OpenGL extension. */
540 /* We advertise as many WINED3D_MULTISAMPLE_NON_MASKABLE quality
541 * levels as the count of advertised multisample types for the texture
542 * format. */
543 if (texture->resource.multisample_type == WINED3D_MULTISAMPLE_NON_MASKABLE)
545 unsigned int i, count = 0;
547 for (i = 0; i < sizeof(format->multisample_types) * CHAR_BIT; ++i)
549 if (format->multisample_types & 1u << i)
551 if (texture->resource.multisample_quality == count++)
552 break;
555 return i + 1;
558 return texture->resource.multisample_type;
561 /* Context activation is done by the caller. */
562 /* The caller is responsible for binding the correct texture. */
563 static void wined3d_texture_allocate_gl_mutable_storage(struct wined3d_texture *texture,
564 GLenum gl_internal_format, const struct wined3d_format *format,
565 const struct wined3d_gl_info *gl_info)
567 unsigned int level, level_count, layer, layer_count;
568 GLsizei width, height, depth;
569 GLenum target;
571 level_count = texture->level_count;
572 if (texture->target == GL_TEXTURE_1D_ARRAY || texture->target == GL_TEXTURE_2D_ARRAY)
573 layer_count = 1;
574 else
575 layer_count = texture->layer_count;
577 for (layer = 0; layer < layer_count; ++layer)
579 target = wined3d_texture_get_sub_resource_target(texture, layer * level_count);
581 for (level = 0; level < level_count; ++level)
583 width = wined3d_texture_get_level_pow2_width(texture, level);
584 height = wined3d_texture_get_level_pow2_height(texture, level);
585 if (texture->resource.format_flags & WINED3DFMT_FLAG_HEIGHT_SCALE)
587 height *= format->height_scale.numerator;
588 height /= format->height_scale.denominator;
591 TRACE("texture %p, layer %u, level %u, target %#x, width %u, height %u.\n",
592 texture, layer, level, target, width, height);
594 if (target == GL_TEXTURE_3D || target == GL_TEXTURE_2D_ARRAY)
596 depth = wined3d_texture_get_level_depth(texture, level);
597 GL_EXTCALL(glTexImage3D(target, level, gl_internal_format, width, height,
598 target == GL_TEXTURE_2D_ARRAY ? texture->layer_count : depth, 0,
599 format->glFormat, format->glType, NULL));
600 checkGLcall("glTexImage3D");
602 else if (target == GL_TEXTURE_1D)
604 gl_info->gl_ops.gl.p_glTexImage1D(target, level, gl_internal_format,
605 width, 0, format->glFormat, format->glType, NULL);
607 else
609 gl_info->gl_ops.gl.p_glTexImage2D(target, level, gl_internal_format, width,
610 target == GL_TEXTURE_1D_ARRAY ? texture->layer_count : height, 0,
611 format->glFormat, format->glType, NULL);
612 checkGLcall("glTexImage2D");
618 /* Context activation is done by the caller. */
619 /* The caller is responsible for binding the correct texture. */
620 static void wined3d_texture_allocate_gl_immutable_storage(struct wined3d_texture *texture,
621 GLenum gl_internal_format, const struct wined3d_gl_info *gl_info)
623 unsigned int samples = wined3d_texture_get_gl_sample_count(texture);
624 GLsizei height = wined3d_texture_get_level_pow2_height(texture, 0);
625 GLsizei width = wined3d_texture_get_level_pow2_width(texture, 0);
627 switch (texture->target)
629 case GL_TEXTURE_3D:
630 GL_EXTCALL(glTexStorage3D(texture->target, texture->level_count,
631 gl_internal_format, width, height, wined3d_texture_get_level_depth(texture, 0)));
632 break;
633 case GL_TEXTURE_2D_ARRAY:
634 GL_EXTCALL(glTexStorage3D(texture->target, texture->level_count,
635 gl_internal_format, width, height, texture->layer_count));
636 break;
637 case GL_TEXTURE_2D_MULTISAMPLE:
638 GL_EXTCALL(glTexStorage2DMultisample(texture->target, samples,
639 gl_internal_format, width, height, GL_FALSE));
640 break;
641 case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
642 GL_EXTCALL(glTexStorage3DMultisample(texture->target, samples,
643 gl_internal_format, width, height, texture->layer_count, GL_FALSE));
644 break;
645 case GL_TEXTURE_1D_ARRAY:
646 GL_EXTCALL(glTexStorage2D(texture->target, texture->level_count,
647 gl_internal_format, width, texture->layer_count));
648 break;
649 case GL_TEXTURE_1D:
650 GL_EXTCALL(glTexStorage1D(texture->target, texture->level_count, gl_internal_format, width));
651 break;
652 default:
653 GL_EXTCALL(glTexStorage2D(texture->target, texture->level_count,
654 gl_internal_format, width, height));
655 break;
658 checkGLcall("allocate immutable storage");
661 static void wined3d_texture_unload_gl_texture(struct wined3d_texture *texture)
663 struct wined3d_device *device = texture->resource.device;
664 const struct wined3d_gl_info *gl_info = NULL;
665 struct wined3d_context *context = NULL;
667 if (texture->texture_rgb.name || texture->texture_srgb.name
668 || texture->rb_multisample || texture->rb_resolved)
670 context = context_acquire(device, NULL, 0);
671 gl_info = context->gl_info;
674 if (texture->texture_rgb.name)
675 gltexture_delete(device, context->gl_info, &texture->texture_rgb);
677 if (texture->texture_srgb.name)
678 gltexture_delete(device, context->gl_info, &texture->texture_srgb);
680 if (texture->rb_multisample)
682 TRACE("Deleting multisample renderbuffer %u.\n", texture->rb_multisample);
683 context_gl_resource_released(device, texture->rb_multisample, TRUE);
684 gl_info->fbo_ops.glDeleteRenderbuffers(1, &texture->rb_multisample);
685 texture->rb_multisample = 0;
688 if (texture->rb_resolved)
690 TRACE("Deleting resolved renderbuffer %u.\n", texture->rb_resolved);
691 context_gl_resource_released(device, texture->rb_resolved, TRUE);
692 gl_info->fbo_ops.glDeleteRenderbuffers(1, &texture->rb_resolved);
693 texture->rb_resolved = 0;
696 if (context) context_release(context);
698 wined3d_texture_set_dirty(texture);
700 resource_unload(&texture->resource);
703 static void wined3d_texture_sub_resources_destroyed(struct wined3d_texture *texture)
705 unsigned int sub_count = texture->level_count * texture->layer_count;
706 struct wined3d_texture_sub_resource *sub_resource;
707 unsigned int i;
709 for (i = 0; i < sub_count; ++i)
711 sub_resource = &texture->sub_resources[i];
712 if (sub_resource->parent)
714 TRACE("sub-resource %u.\n", i);
715 sub_resource->parent_ops->wined3d_object_destroyed(sub_resource->parent);
716 sub_resource->parent = NULL;
721 static void wined3d_texture_create_dc(void *object)
723 const struct wined3d_texture_idx *idx = object;
724 struct wined3d_context *context = NULL;
725 unsigned int sub_resource_idx, level;
726 const struct wined3d_format *format;
727 unsigned int row_pitch, slice_pitch;
728 struct wined3d_texture *texture;
729 struct wined3d_dc_info *dc_info;
730 struct wined3d_bo_address data;
731 D3DKMT_CREATEDCFROMMEMORY desc;
732 struct wined3d_device *device;
733 NTSTATUS status;
735 TRACE("texture %p, sub_resource_idx %u.\n", idx->texture, idx->sub_resource_idx);
737 texture = idx->texture;
738 sub_resource_idx = idx->sub_resource_idx;
739 level = sub_resource_idx % texture->level_count;
740 device = texture->resource.device;
742 format = texture->resource.format;
743 if (!format->ddi_format)
745 WARN("Cannot create a DC for format %s.\n", debug_d3dformat(format->id));
746 return;
749 if (!texture->dc_info)
751 unsigned int sub_count = texture->level_count * texture->layer_count;
753 if (!(texture->dc_info = heap_calloc(sub_count, sizeof(*texture->dc_info))))
755 ERR("Failed to allocate DC info.\n");
756 return;
760 if (device->d3d_initialized)
761 context = context_acquire(device, NULL, 0);
763 wined3d_texture_load_location(texture, sub_resource_idx, context, texture->resource.map_binding);
764 wined3d_texture_invalidate_location(texture, sub_resource_idx, ~texture->resource.map_binding);
765 wined3d_texture_get_pitch(texture, level, &row_pitch, &slice_pitch);
766 wined3d_texture_get_memory(texture, sub_resource_idx, &data, texture->resource.map_binding);
767 desc.pMemory = context_map_bo_address(context, &data,
768 texture->sub_resources[sub_resource_idx].size,
769 GL_PIXEL_UNPACK_BUFFER, WINED3D_MAP_READ | WINED3D_MAP_WRITE);
771 if (context)
772 context_release(context);
774 desc.Format = format->ddi_format;
775 desc.Width = wined3d_texture_get_level_width(texture, level);
776 desc.Height = wined3d_texture_get_level_height(texture, level);
777 desc.Pitch = row_pitch;
778 desc.hDeviceDc = CreateCompatibleDC(NULL);
779 desc.pColorTable = NULL;
781 status = D3DKMTCreateDCFromMemory(&desc);
782 DeleteDC(desc.hDeviceDc);
783 if (status)
785 WARN("Failed to create DC, status %#x.\n", status);
786 return;
789 dc_info = &texture->dc_info[sub_resource_idx];
790 dc_info->dc = desc.hDc;
791 dc_info->bitmap = desc.hBitmap;
793 TRACE("Created DC %p, bitmap %p for texture %p, %u.\n", dc_info->dc, dc_info->bitmap, texture, sub_resource_idx);
796 static void wined3d_texture_destroy_dc(void *object)
798 const struct wined3d_texture_idx *idx = object;
799 D3DKMT_DESTROYDCFROMMEMORY destroy_desc;
800 struct wined3d_context *context = NULL;
801 struct wined3d_texture *texture;
802 struct wined3d_dc_info *dc_info;
803 struct wined3d_bo_address data;
804 unsigned int sub_resource_idx;
805 struct wined3d_device *device;
806 NTSTATUS status;
808 texture = idx->texture;
809 sub_resource_idx = idx->sub_resource_idx;
810 device = texture->resource.device;
811 dc_info = &texture->dc_info[sub_resource_idx];
813 if (!dc_info->dc)
815 ERR("Sub-resource {%p, %u} has no DC.\n", texture, sub_resource_idx);
816 return;
819 TRACE("dc %p, bitmap %p.\n", dc_info->dc, dc_info->bitmap);
821 destroy_desc.hDc = dc_info->dc;
822 destroy_desc.hBitmap = dc_info->bitmap;
823 if ((status = D3DKMTDestroyDCFromMemory(&destroy_desc)))
824 ERR("Failed to destroy dc, status %#x.\n", status);
825 dc_info->dc = NULL;
826 dc_info->bitmap = NULL;
828 if (device->d3d_initialized)
829 context = context_acquire(device, NULL, 0);
831 wined3d_texture_get_memory(texture, sub_resource_idx, &data, texture->resource.map_binding);
832 context_unmap_bo_address(context, &data, GL_PIXEL_UNPACK_BUFFER);
834 if (context)
835 context_release(context);
838 static void wined3d_texture_cleanup(struct wined3d_texture *texture)
840 unsigned int sub_count = texture->level_count * texture->layer_count;
841 struct wined3d_device *device = texture->resource.device;
842 struct wined3d_renderbuffer_entry *entry, *entry2;
843 const struct wined3d_gl_info *gl_info = NULL;
844 struct wined3d_context *context = NULL;
845 struct wined3d_dc_info *dc_info;
846 GLuint buffer_object;
847 unsigned int i;
849 TRACE("texture %p.\n", texture);
851 for (i = 0; i < sub_count; ++i)
853 if (!(buffer_object = texture->sub_resources[i].buffer_object))
854 continue;
856 TRACE("Deleting buffer object %u.\n", buffer_object);
858 /* We may not be able to get a context in wined3d_texture_cleanup() in
859 * general, but if a buffer object was previously created we can. */
860 if (!context)
862 context = context_acquire(device, NULL, 0);
863 gl_info = context->gl_info;
866 GL_EXTCALL(glDeleteBuffers(1, &buffer_object));
869 if (!context && !list_empty(&texture->renderbuffers))
871 context = context_acquire(device, NULL, 0);
872 gl_info = context->gl_info;
875 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &texture->renderbuffers, struct wined3d_renderbuffer_entry, entry)
877 TRACE("Deleting renderbuffer %u.\n", entry->id);
878 context_gl_resource_released(device, entry->id, TRUE);
879 gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id);
880 heap_free(entry);
883 if (context)
884 context_release(context);
886 if ((dc_info = texture->dc_info))
888 for (i = 0; i < sub_count; ++i)
890 if (dc_info[i].dc)
892 struct wined3d_texture_idx texture_idx = {texture, i};
894 wined3d_texture_destroy_dc(&texture_idx);
897 heap_free(dc_info);
900 if (texture->overlay_info)
902 for (i = 0; i < sub_count; ++i)
904 struct wined3d_overlay_info *info = &texture->overlay_info[i];
905 struct wined3d_overlay_info *overlay, *cur;
907 list_remove(&info->entry);
908 LIST_FOR_EACH_ENTRY_SAFE(overlay, cur, &info->overlays, struct wined3d_overlay_info, entry)
910 list_remove(&overlay->entry);
913 heap_free(texture->overlay_info);
915 wined3d_texture_unload_gl_texture(texture);
918 void wined3d_texture_set_swapchain(struct wined3d_texture *texture, struct wined3d_swapchain *swapchain)
920 texture->swapchain = swapchain;
921 wined3d_resource_update_draw_binding(&texture->resource);
924 /* Context activation is done by the caller. */
925 void wined3d_texture_bind(struct wined3d_texture *texture,
926 struct wined3d_context *context, BOOL srgb)
928 const struct wined3d_gl_info *gl_info = context->gl_info;
929 const struct wined3d_format *format = texture->resource.format;
930 const struct color_fixup_desc fixup = format->color_fixup;
931 struct gl_texture *gl_tex;
932 GLenum target;
934 TRACE("texture %p, context %p, srgb %#x.\n", texture, context, srgb);
936 if (!needs_separate_srgb_gl_texture(context, texture))
937 srgb = FALSE;
939 /* sRGB mode cache for preload() calls outside drawprim. */
940 if (srgb)
941 texture->flags |= WINED3D_TEXTURE_IS_SRGB;
942 else
943 texture->flags &= ~WINED3D_TEXTURE_IS_SRGB;
945 gl_tex = wined3d_texture_get_gl_texture(texture, srgb);
946 target = texture->target;
948 if (gl_tex->name)
950 context_bind_texture(context, target, gl_tex->name);
951 return;
954 gl_info->gl_ops.gl.p_glGenTextures(1, &gl_tex->name);
955 checkGLcall("glGenTextures");
956 TRACE("Generated texture %d.\n", gl_tex->name);
958 if (!gl_tex->name)
960 ERR("Failed to generate a texture name.\n");
961 return;
964 /* Initialise the state of the texture object to the OpenGL defaults, not
965 * the wined3d defaults. */
966 gl_tex->sampler_desc.address_u = WINED3D_TADDRESS_WRAP;
967 gl_tex->sampler_desc.address_v = WINED3D_TADDRESS_WRAP;
968 gl_tex->sampler_desc.address_w = WINED3D_TADDRESS_WRAP;
969 memset(gl_tex->sampler_desc.border_color, 0, sizeof(gl_tex->sampler_desc.border_color));
970 gl_tex->sampler_desc.mag_filter = WINED3D_TEXF_LINEAR;
971 gl_tex->sampler_desc.min_filter = WINED3D_TEXF_POINT; /* GL_NEAREST_MIPMAP_LINEAR */
972 gl_tex->sampler_desc.mip_filter = WINED3D_TEXF_LINEAR; /* GL_NEAREST_MIPMAP_LINEAR */
973 gl_tex->sampler_desc.lod_bias = 0.0f;
974 gl_tex->sampler_desc.min_lod = -1000.0f;
975 gl_tex->sampler_desc.max_lod = 1000.0f;
976 gl_tex->sampler_desc.max_anisotropy = 1;
977 gl_tex->sampler_desc.compare = FALSE;
978 gl_tex->sampler_desc.comparison_func = WINED3D_CMP_LESSEQUAL;
979 if (context->gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
980 gl_tex->sampler_desc.srgb_decode = TRUE;
981 else
982 gl_tex->sampler_desc.srgb_decode = srgb;
983 gl_tex->base_level = 0;
984 wined3d_texture_set_dirty(texture);
986 context_bind_texture(context, target, gl_tex->name);
988 /* For a new texture we have to set the texture levels after binding the
989 * texture. Beware that texture rectangles do not support mipmapping, but
990 * set the maxmiplevel if we're relying on the partial
991 * GL_ARB_texture_non_power_of_two emulation with texture rectangles.
992 * (I.e., do not care about cond_np2 here, just look for
993 * GL_TEXTURE_RECTANGLE_ARB.) */
994 if (target != GL_TEXTURE_RECTANGLE_ARB)
996 TRACE("Setting GL_TEXTURE_MAX_LEVEL to %u.\n", texture->level_count - 1);
997 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, texture->level_count - 1);
998 checkGLcall("glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, texture->level_count)");
1001 if (target == GL_TEXTURE_CUBE_MAP_ARB)
1003 /* Cubemaps are always set to clamp, regardless of the sampler state. */
1004 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1005 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1006 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
1009 if (texture->flags & WINED3D_TEXTURE_COND_NP2)
1011 /* Conditinal non power of two textures use a different clamping
1012 * default. If we're using the GL_WINE_normalized_texrect partial
1013 * driver emulation, we're dealing with a GL_TEXTURE_2D texture which
1014 * has the address mode set to repeat - something that prevents us
1015 * from hitting the accelerated codepath. Thus manually set the GL
1016 * state. The same applies to filtering. Even if the texture has only
1017 * one mip level, the default LINEAR_MIPMAP_LINEAR filter causes a SW
1018 * fallback on macos. */
1019 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1020 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1021 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1022 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1023 checkGLcall("glTexParameteri");
1024 gl_tex->sampler_desc.address_u = WINED3D_TADDRESS_CLAMP;
1025 gl_tex->sampler_desc.address_v = WINED3D_TADDRESS_CLAMP;
1026 gl_tex->sampler_desc.mag_filter = WINED3D_TEXF_POINT;
1027 gl_tex->sampler_desc.min_filter = WINED3D_TEXF_POINT;
1028 gl_tex->sampler_desc.mip_filter = WINED3D_TEXF_NONE;
1031 if (gl_info->supported[WINED3D_GL_LEGACY_CONTEXT] && gl_info->supported[ARB_DEPTH_TEXTURE])
1033 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY);
1034 checkGLcall("glTexParameteri(GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY)");
1037 if (!is_identity_fixup(fixup) && can_use_texture_swizzle(gl_info, format))
1039 static const GLenum swizzle_source[] =
1041 GL_ZERO, /* CHANNEL_SOURCE_ZERO */
1042 GL_ONE, /* CHANNEL_SOURCE_ONE */
1043 GL_RED, /* CHANNEL_SOURCE_X */
1044 GL_GREEN, /* CHANNEL_SOURCE_Y */
1045 GL_BLUE, /* CHANNEL_SOURCE_Z */
1046 GL_ALPHA, /* CHANNEL_SOURCE_W */
1048 struct
1050 GLint x, y, z, w;
1052 swizzle;
1054 swizzle.x = swizzle_source[fixup.x_source];
1055 swizzle.y = swizzle_source[fixup.y_source];
1056 swizzle.z = swizzle_source[fixup.z_source];
1057 swizzle.w = swizzle_source[fixup.w_source];
1058 gl_info->gl_ops.gl.p_glTexParameteriv(target, GL_TEXTURE_SWIZZLE_RGBA, &swizzle.x);
1059 checkGLcall("glTexParameteriv(GL_TEXTURE_SWIZZLE_RGBA)");
1063 /* Context activation is done by the caller. */
1064 void wined3d_texture_bind_and_dirtify(struct wined3d_texture *texture,
1065 struct wined3d_context *context, BOOL srgb)
1067 /* We don't need a specific texture unit, but after binding the texture
1068 * the current unit is dirty. Read the unit back instead of switching to
1069 * 0, this avoids messing around with the state manager's GL states. The
1070 * current texture unit should always be a valid one.
1072 * To be more specific, this is tricky because we can implicitly be
1073 * called from sampler() in state.c. This means we can't touch anything
1074 * other than whatever happens to be the currently active texture, or we
1075 * would risk marking already applied sampler states dirty again. */
1076 if (context->active_texture < ARRAY_SIZE(context->rev_tex_unit_map))
1078 DWORD active_sampler = context->rev_tex_unit_map[context->active_texture];
1079 if (active_sampler != WINED3D_UNMAPPED_STAGE)
1080 context_invalidate_state(context, STATE_SAMPLER(active_sampler));
1082 /* FIXME: Ideally we'd only do this when touching a binding that's used by
1083 * a shader. */
1084 context_invalidate_compute_state(context, STATE_COMPUTE_SHADER_RESOURCE_BINDING);
1085 context_invalidate_state(context, STATE_GRAPHICS_SHADER_RESOURCE_BINDING);
1087 wined3d_texture_bind(texture, context, srgb);
1090 /* Context activation is done by the caller (state handler). */
1091 /* This function relies on the correct texture being bound and loaded. */
1092 void wined3d_texture_apply_sampler_desc(struct wined3d_texture *texture,
1093 const struct wined3d_sampler_desc *sampler_desc, const struct wined3d_context *context)
1095 const struct wined3d_gl_info *gl_info = context->gl_info;
1096 GLenum target = texture->target;
1097 struct gl_texture *gl_tex;
1098 DWORD state;
1100 TRACE("texture %p, sampler_desc %p, context %p.\n", texture, sampler_desc, context);
1102 gl_tex = wined3d_texture_get_gl_texture(texture, texture->flags & WINED3D_TEXTURE_IS_SRGB);
1104 state = sampler_desc->address_u;
1105 if (state != gl_tex->sampler_desc.address_u)
1107 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_S,
1108 gl_info->wrap_lookup[state - WINED3D_TADDRESS_WRAP]);
1109 gl_tex->sampler_desc.address_u = state;
1112 state = sampler_desc->address_v;
1113 if (state != gl_tex->sampler_desc.address_v)
1115 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_T,
1116 gl_info->wrap_lookup[state - WINED3D_TADDRESS_WRAP]);
1117 gl_tex->sampler_desc.address_v = state;
1120 state = sampler_desc->address_w;
1121 if (state != gl_tex->sampler_desc.address_w)
1123 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_R,
1124 gl_info->wrap_lookup[state - WINED3D_TADDRESS_WRAP]);
1125 gl_tex->sampler_desc.address_w = state;
1128 if (memcmp(gl_tex->sampler_desc.border_color, sampler_desc->border_color,
1129 sizeof(gl_tex->sampler_desc.border_color)))
1131 gl_info->gl_ops.gl.p_glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, &sampler_desc->border_color[0]);
1132 memcpy(gl_tex->sampler_desc.border_color, sampler_desc->border_color,
1133 sizeof(gl_tex->sampler_desc.border_color));
1136 state = sampler_desc->mag_filter;
1137 if (state != gl_tex->sampler_desc.mag_filter)
1139 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MAG_FILTER, wined3d_gl_mag_filter(state));
1140 gl_tex->sampler_desc.mag_filter = state;
1143 if (sampler_desc->min_filter != gl_tex->sampler_desc.min_filter
1144 || sampler_desc->mip_filter != gl_tex->sampler_desc.mip_filter)
1146 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MIN_FILTER,
1147 wined3d_gl_min_mip_filter(sampler_desc->min_filter, sampler_desc->mip_filter));
1148 gl_tex->sampler_desc.min_filter = sampler_desc->min_filter;
1149 gl_tex->sampler_desc.mip_filter = sampler_desc->mip_filter;
1152 state = sampler_desc->max_anisotropy;
1153 if (state != gl_tex->sampler_desc.max_anisotropy)
1155 if (gl_info->supported[ARB_TEXTURE_FILTER_ANISOTROPIC])
1156 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MAX_ANISOTROPY, state);
1157 else
1158 WARN("Anisotropic filtering not supported.\n");
1159 gl_tex->sampler_desc.max_anisotropy = state;
1162 if (!sampler_desc->srgb_decode != !gl_tex->sampler_desc.srgb_decode
1163 && (context->d3d_info->wined3d_creation_flags & WINED3D_SRGB_READ_WRITE_CONTROL)
1164 && gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
1166 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_SRGB_DECODE_EXT,
1167 sampler_desc->srgb_decode ? GL_DECODE_EXT : GL_SKIP_DECODE_EXT);
1168 gl_tex->sampler_desc.srgb_decode = sampler_desc->srgb_decode;
1171 if (!sampler_desc->compare != !gl_tex->sampler_desc.compare)
1173 if (sampler_desc->compare)
1174 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
1175 else
1176 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
1177 gl_tex->sampler_desc.compare = sampler_desc->compare;
1180 checkGLcall("Texture parameter application");
1182 if (gl_info->supported[EXT_TEXTURE_LOD_BIAS])
1184 gl_info->gl_ops.gl.p_glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT,
1185 GL_TEXTURE_LOD_BIAS_EXT, sampler_desc->lod_bias);
1186 checkGLcall("glTexEnvf(GL_TEXTURE_LOD_BIAS_EXT, ...)");
1190 ULONG CDECL wined3d_texture_incref(struct wined3d_texture *texture)
1192 ULONG refcount;
1194 TRACE("texture %p, swapchain %p.\n", texture, texture->swapchain);
1196 if (texture->swapchain)
1197 return wined3d_swapchain_incref(texture->swapchain);
1199 refcount = InterlockedIncrement(&texture->resource.ref);
1200 TRACE("%p increasing refcount to %u.\n", texture, refcount);
1202 return refcount;
1205 static void wined3d_texture_cleanup_sync(struct wined3d_texture *texture)
1207 wined3d_texture_sub_resources_destroyed(texture);
1208 resource_cleanup(&texture->resource);
1209 wined3d_resource_wait_idle(&texture->resource);
1210 wined3d_texture_cleanup(texture);
1213 static void wined3d_texture_destroy_object(void *object)
1215 wined3d_texture_cleanup(object);
1216 heap_free(object);
1219 ULONG CDECL wined3d_texture_decref(struct wined3d_texture *texture)
1221 ULONG refcount;
1223 TRACE("texture %p, swapchain %p.\n", texture, texture->swapchain);
1225 if (texture->swapchain)
1226 return wined3d_swapchain_decref(texture->swapchain);
1228 refcount = InterlockedDecrement(&texture->resource.ref);
1229 TRACE("%p decreasing refcount to %u.\n", texture, refcount);
1231 if (!refcount)
1233 /* Wait for the texture to become idle if it's using user memory,
1234 * since the application is allowed to free that memory once the
1235 * texture is destroyed. Note that this implies that
1236 * wined3d_texture_destroy_object() can't access that memory either. */
1237 if (texture->user_memory)
1238 wined3d_resource_wait_idle(&texture->resource);
1239 wined3d_texture_sub_resources_destroyed(texture);
1240 texture->resource.parent_ops->wined3d_object_destroyed(texture->resource.parent);
1241 resource_cleanup(&texture->resource);
1242 wined3d_cs_destroy_object(texture->resource.device->cs, wined3d_texture_destroy_object, texture);
1245 return refcount;
1248 struct wined3d_resource * CDECL wined3d_texture_get_resource(struct wined3d_texture *texture)
1250 TRACE("texture %p.\n", texture);
1252 return &texture->resource;
1255 static BOOL color_key_equal(const struct wined3d_color_key *c1, struct wined3d_color_key *c2)
1257 return c1->color_space_low_value == c2->color_space_low_value
1258 && c1->color_space_high_value == c2->color_space_high_value;
1261 /* Context activation is done by the caller */
1262 void wined3d_texture_load(struct wined3d_texture *texture,
1263 struct wined3d_context *context, BOOL srgb)
1265 UINT sub_count = texture->level_count * texture->layer_count;
1266 const struct wined3d_d3d_info *d3d_info = context->d3d_info;
1267 DWORD flag;
1268 UINT i;
1270 TRACE("texture %p, context %p, srgb %#x.\n", texture, context, srgb);
1272 if (!needs_separate_srgb_gl_texture(context, texture))
1273 srgb = FALSE;
1275 if (srgb)
1276 flag = WINED3D_TEXTURE_SRGB_VALID;
1277 else
1278 flag = WINED3D_TEXTURE_RGB_VALID;
1280 if (!d3d_info->shader_color_key
1281 && (!(texture->async.flags & WINED3D_TEXTURE_ASYNC_COLOR_KEY)
1282 != !(texture->async.color_key_flags & WINED3D_CKEY_SRC_BLT)
1283 || (texture->async.flags & WINED3D_TEXTURE_ASYNC_COLOR_KEY
1284 && !color_key_equal(&texture->async.gl_color_key, &texture->async.src_blt_color_key))))
1286 unsigned int sub_count = texture->level_count * texture->layer_count;
1287 unsigned int i;
1289 TRACE("Reloading because of color key value change.\n");
1290 for (i = 0; i < sub_count; i++)
1292 if (!wined3d_texture_load_location(texture, i, context, texture->resource.map_binding))
1293 ERR("Failed to load location %s.\n", wined3d_debug_location(texture->resource.map_binding));
1294 else
1295 wined3d_texture_invalidate_location(texture, i, ~texture->resource.map_binding);
1298 texture->async.gl_color_key = texture->async.src_blt_color_key;
1301 if (texture->flags & flag)
1303 TRACE("Texture %p not dirty, nothing to do.\n", texture);
1304 return;
1307 /* Reload the surfaces if the texture is marked dirty. */
1308 for (i = 0; i < sub_count; ++i)
1310 if (!wined3d_texture_load_location(texture, i, context,
1311 srgb ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB))
1312 ERR("Failed to load location (srgb %#x).\n", srgb);
1314 texture->flags |= flag;
1317 void * CDECL wined3d_texture_get_parent(const struct wined3d_texture *texture)
1319 TRACE("texture %p.\n", texture);
1321 return texture->resource.parent;
1324 HRESULT wined3d_texture_check_box_dimensions(const struct wined3d_texture *texture,
1325 unsigned int level, const struct wined3d_box *box)
1327 const struct wined3d_format *format = texture->resource.format;
1328 unsigned int width_mask, height_mask, width, height, depth;
1330 width = wined3d_texture_get_level_width(texture, level);
1331 height = wined3d_texture_get_level_height(texture, level);
1332 depth = wined3d_texture_get_level_depth(texture, level);
1334 if (box->left >= box->right || box->right > width
1335 || box->top >= box->bottom || box->bottom > height
1336 || box->front >= box->back || box->back > depth)
1338 WARN("Box %s is invalid.\n", debug_box(box));
1339 return WINEDDERR_INVALIDRECT;
1342 if (texture->resource.format_flags & WINED3DFMT_FLAG_BLOCKS)
1344 /* This assumes power of two block sizes, but NPOT block sizes would
1345 * be silly anyway.
1347 * This also assumes that the format's block depth is 1. */
1348 width_mask = format->block_width - 1;
1349 height_mask = format->block_height - 1;
1351 if ((box->left & width_mask) || (box->top & height_mask)
1352 || (box->right & width_mask && box->right != width)
1353 || (box->bottom & height_mask && box->bottom != height))
1355 WARN("Box %s is misaligned for %ux%u blocks.\n",
1356 debug_box(box), format->block_width, format->block_height);
1357 return WINED3DERR_INVALIDCALL;
1361 return WINED3D_OK;
1364 void CDECL wined3d_texture_get_pitch(const struct wined3d_texture *texture,
1365 unsigned int level, unsigned int *row_pitch, unsigned int *slice_pitch)
1367 const struct wined3d_resource *resource = &texture->resource;
1368 unsigned int width = wined3d_texture_get_level_width(texture, level);
1369 unsigned int height = wined3d_texture_get_level_height(texture, level);
1371 if (texture->row_pitch)
1373 *row_pitch = texture->row_pitch;
1374 *slice_pitch = texture->slice_pitch;
1375 return;
1378 wined3d_format_calculate_pitch(resource->format, resource->device->surface_alignment,
1379 width, height, row_pitch, slice_pitch);
1382 DWORD CDECL wined3d_texture_set_lod(struct wined3d_texture *texture, DWORD lod)
1384 DWORD old = texture->lod;
1386 TRACE("texture %p, lod %u.\n", texture, lod);
1388 /* The d3d9:texture test shows that SetLOD is ignored on non-managed
1389 * textures. The call always returns 0, and GetLOD always returns 0. */
1390 if (!wined3d_resource_access_is_managed(texture->resource.access))
1392 TRACE("Ignoring LOD on texture with resource access %s.\n",
1393 wined3d_debug_resource_access(texture->resource.access));
1394 return 0;
1397 if (lod >= texture->level_count)
1398 lod = texture->level_count - 1;
1400 if (texture->lod != lod)
1402 struct wined3d_device *device = texture->resource.device;
1404 wined3d_resource_wait_idle(&texture->resource);
1405 texture->lod = lod;
1407 texture->texture_rgb.base_level = ~0u;
1408 texture->texture_srgb.base_level = ~0u;
1409 if (texture->resource.bind_count)
1410 wined3d_cs_emit_set_sampler_state(device->cs, texture->sampler, WINED3D_SAMP_MAX_MIP_LEVEL,
1411 device->state.sampler_states[texture->sampler][WINED3D_SAMP_MAX_MIP_LEVEL]);
1414 return old;
1417 DWORD CDECL wined3d_texture_get_lod(const struct wined3d_texture *texture)
1419 TRACE("texture %p, returning %u.\n", texture, texture->lod);
1421 return texture->lod;
1424 DWORD CDECL wined3d_texture_get_level_count(const struct wined3d_texture *texture)
1426 TRACE("texture %p, returning %u.\n", texture, texture->level_count);
1428 return texture->level_count;
1431 HRESULT CDECL wined3d_texture_set_color_key(struct wined3d_texture *texture,
1432 DWORD flags, const struct wined3d_color_key *color_key)
1434 struct wined3d_device *device = texture->resource.device;
1435 static const DWORD all_flags = WINED3D_CKEY_DST_BLT | WINED3D_CKEY_DST_OVERLAY
1436 | WINED3D_CKEY_SRC_BLT | WINED3D_CKEY_SRC_OVERLAY;
1438 TRACE("texture %p, flags %#x, color_key %p.\n", texture, flags, color_key);
1440 if (flags & ~all_flags)
1442 WARN("Invalid flags passed, returning WINED3DERR_INVALIDCALL.\n");
1443 return WINED3DERR_INVALIDCALL;
1446 wined3d_cs_emit_set_color_key(device->cs, texture, flags, color_key);
1448 return WINED3D_OK;
1451 /* In D3D the depth stencil dimensions have to be greater than or equal to the
1452 * render target dimensions. With FBOs, the dimensions have to be an exact match. */
1453 /* TODO: We should synchronize the renderbuffer's content with the texture's content. */
1454 /* Context activation is done by the caller. */
1455 void wined3d_texture_set_compatible_renderbuffer(struct wined3d_texture *texture,
1456 unsigned int level, const struct wined3d_rendertarget_info *rt)
1458 struct wined3d_renderbuffer_entry *entry;
1459 const struct wined3d_gl_info *gl_info;
1460 unsigned int src_width, src_height;
1461 unsigned int width, height;
1462 GLuint renderbuffer = 0;
1464 gl_info = &texture->resource.device->adapter->gl_info;
1465 if (gl_info->supported[ARB_FRAMEBUFFER_OBJECT])
1466 return;
1468 if (rt && rt->resource->format->id != WINED3DFMT_NULL)
1470 struct wined3d_texture *rt_texture;
1471 unsigned int rt_level;
1473 if (rt->resource->type == WINED3D_RTYPE_BUFFER)
1475 FIXME("Unsupported resource type %s.\n", debug_d3dresourcetype(rt->resource->type));
1476 return;
1478 rt_texture = wined3d_texture_from_resource(rt->resource);
1479 rt_level = rt->sub_resource_idx % rt_texture->level_count;
1481 width = wined3d_texture_get_level_pow2_width(rt_texture, rt_level);
1482 height = wined3d_texture_get_level_pow2_height(rt_texture, rt_level);
1484 else
1486 width = wined3d_texture_get_level_pow2_width(texture, level);
1487 height = wined3d_texture_get_level_pow2_height(texture, level);
1490 src_width = wined3d_texture_get_level_pow2_width(texture, level);
1491 src_height = wined3d_texture_get_level_pow2_height(texture, level);
1493 /* A depth stencil smaller than the render target is not valid */
1494 if (width > src_width || height > src_height)
1495 return;
1497 /* Remove any renderbuffer set if the sizes match */
1498 if (width == src_width && height == src_height)
1500 texture->current_renderbuffer = NULL;
1501 return;
1504 /* Look if we've already got a renderbuffer of the correct dimensions */
1505 LIST_FOR_EACH_ENTRY(entry, &texture->renderbuffers, struct wined3d_renderbuffer_entry, entry)
1507 if (entry->width == width && entry->height == height)
1509 renderbuffer = entry->id;
1510 texture->current_renderbuffer = entry;
1511 break;
1515 if (!renderbuffer)
1517 gl_info->fbo_ops.glGenRenderbuffers(1, &renderbuffer);
1518 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
1519 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER,
1520 texture->resource.format->glInternal, width, height);
1522 entry = heap_alloc(sizeof(*entry));
1523 entry->width = width;
1524 entry->height = height;
1525 entry->id = renderbuffer;
1526 list_add_head(&texture->renderbuffers, &entry->entry);
1528 texture->current_renderbuffer = entry;
1531 checkGLcall("set_compatible_renderbuffer");
1534 HRESULT CDECL wined3d_texture_update_desc(struct wined3d_texture *texture, UINT width, UINT height,
1535 enum wined3d_format_id format_id, enum wined3d_multisample_type multisample_type,
1536 UINT multisample_quality, void *mem, UINT pitch)
1538 struct wined3d_device *device = texture->resource.device;
1539 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1540 const struct wined3d_format *format = wined3d_get_format(gl_info, format_id, texture->resource.usage);
1541 UINT resource_size = wined3d_format_calculate_size(format, device->surface_alignment, width, height, 1);
1542 struct wined3d_texture_sub_resource *sub_resource;
1543 DWORD valid_location = 0;
1544 BOOL create_dib = FALSE;
1546 TRACE("texture %p, width %u, height %u, format %s, multisample_type %#x, multisample_quality %u, "
1547 "mem %p, pitch %u.\n",
1548 texture, width, height, debug_d3dformat(format_id), multisample_type, multisample_quality, mem, pitch);
1550 if (!resource_size)
1551 return WINED3DERR_INVALIDCALL;
1553 if (texture->level_count * texture->layer_count > 1)
1555 WARN("Texture has multiple sub-resources, not supported.\n");
1556 return WINED3DERR_INVALIDCALL;
1559 if (texture->resource.type != WINED3D_RTYPE_TEXTURE_2D)
1561 WARN("Not supported on %s.\n", debug_d3dresourcetype(texture->resource.type));
1562 return WINED3DERR_INVALIDCALL;
1565 if (texture->resource.map_count)
1567 WARN("Texture is mapped.\n");
1568 return WINED3DERR_INVALIDCALL;
1571 /* We have no way of supporting a pitch that is not a multiple of the pixel
1572 * byte width short of uploading the texture row-by-row.
1573 * Fortunately that's not an issue since D3D9Ex doesn't allow a custom pitch
1574 * for user-memory textures (it always expects packed data) while DirectDraw
1575 * requires a 4-byte aligned pitch and doesn't support texture formats
1576 * larger than 4 bytes per pixel nor any format using 3 bytes per pixel.
1577 * This check is here to verify that the assumption holds. */
1578 if (pitch % texture->resource.format->byte_count)
1580 WARN("Pitch unsupported, not a multiple of the texture format byte width.\n");
1581 return WINED3DERR_INVALIDCALL;
1584 if (device->d3d_initialized)
1585 wined3d_cs_emit_unload_resource(device->cs, &texture->resource);
1586 wined3d_resource_wait_idle(&texture->resource);
1588 sub_resource = &texture->sub_resources[0];
1589 if (texture->dc_info && texture->dc_info[0].dc)
1591 struct wined3d_texture_idx texture_idx = {texture, 0};
1593 wined3d_cs_destroy_object(device->cs, wined3d_texture_destroy_dc, &texture_idx);
1594 device->cs->ops->finish(device->cs, WINED3D_CS_QUEUE_DEFAULT);
1595 create_dib = TRUE;
1598 wined3d_resource_free_sysmem(&texture->resource);
1600 if ((texture->row_pitch = pitch))
1601 texture->slice_pitch = height * pitch;
1602 else
1603 /* User memory surfaces don't have the regular surface alignment. */
1604 wined3d_format_calculate_pitch(format, 1, width, height,
1605 &texture->row_pitch, &texture->slice_pitch);
1607 texture->resource.format = format;
1608 texture->resource.multisample_type = multisample_type;
1609 texture->resource.multisample_quality = multisample_quality;
1610 texture->resource.width = width;
1611 texture->resource.height = height;
1612 texture->resource.size = texture->slice_pitch;
1613 sub_resource->size = texture->slice_pitch;
1614 sub_resource->locations = WINED3D_LOCATION_DISCARDED;
1616 if (multisample_type && gl_info->supported[ARB_TEXTURE_MULTISAMPLE])
1617 texture->target = GL_TEXTURE_2D_MULTISAMPLE;
1618 else
1619 texture->target = GL_TEXTURE_2D;
1621 if (((width & (width - 1)) || (height & (height - 1))) && !gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO]
1622 && !gl_info->supported[ARB_TEXTURE_RECTANGLE] && !gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
1624 texture->flags |= WINED3D_TEXTURE_COND_NP2_EMULATED;
1625 texture->pow2_width = texture->pow2_height = 1;
1626 while (texture->pow2_width < width)
1627 texture->pow2_width <<= 1;
1628 while (texture->pow2_height < height)
1629 texture->pow2_height <<= 1;
1631 else
1633 texture->flags &= ~WINED3D_TEXTURE_COND_NP2_EMULATED;
1634 texture->pow2_width = width;
1635 texture->pow2_height = height;
1638 if ((texture->user_memory = mem))
1640 texture->resource.map_binding = WINED3D_LOCATION_USER_MEMORY;
1641 valid_location = WINED3D_LOCATION_USER_MEMORY;
1643 else
1645 wined3d_texture_prepare_location(texture, 0, NULL, WINED3D_LOCATION_SYSMEM);
1646 valid_location = WINED3D_LOCATION_SYSMEM;
1649 /* The format might be changed to a format that needs conversion.
1650 * If the surface didn't use PBOs previously but could now, don't
1651 * change it - whatever made us not use PBOs might come back, e.g.
1652 * color keys. */
1653 if (texture->resource.map_binding == WINED3D_LOCATION_BUFFER && !wined3d_texture_use_pbo(texture, gl_info))
1654 texture->resource.map_binding = WINED3D_LOCATION_SYSMEM;
1656 wined3d_texture_validate_location(texture, 0, valid_location);
1657 wined3d_texture_invalidate_location(texture, 0, ~valid_location);
1659 if (create_dib)
1661 struct wined3d_texture_idx texture_idx = {texture, 0};
1663 wined3d_cs_init_object(device->cs, wined3d_texture_create_dc, &texture_idx);
1664 device->cs->ops->finish(device->cs, WINED3D_CS_QUEUE_DEFAULT);
1667 return WINED3D_OK;
1670 /* Context activation is done by the caller. */
1671 static void wined3d_texture_prepare_buffer_object(struct wined3d_texture *texture,
1672 unsigned int sub_resource_idx, const struct wined3d_gl_info *gl_info)
1674 struct wined3d_texture_sub_resource *sub_resource;
1676 sub_resource = &texture->sub_resources[sub_resource_idx];
1677 if (sub_resource->buffer_object)
1678 return;
1680 GL_EXTCALL(glGenBuffers(1, &sub_resource->buffer_object));
1681 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, sub_resource->buffer_object));
1682 GL_EXTCALL(glBufferData(GL_PIXEL_UNPACK_BUFFER, sub_resource->size, NULL, GL_STREAM_DRAW));
1683 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));
1684 checkGLcall("Create buffer object");
1686 TRACE("Created buffer object %u for texture %p, sub-resource %u.\n",
1687 sub_resource->buffer_object, texture, sub_resource_idx);
1690 static void wined3d_texture_force_reload(struct wined3d_texture *texture)
1692 unsigned int sub_count = texture->level_count * texture->layer_count;
1693 unsigned int i;
1695 texture->flags &= ~(WINED3D_TEXTURE_RGB_ALLOCATED | WINED3D_TEXTURE_SRGB_ALLOCATED
1696 | WINED3D_TEXTURE_CONVERTED);
1697 texture->async.flags &= ~WINED3D_TEXTURE_ASYNC_COLOR_KEY;
1698 for (i = 0; i < sub_count; ++i)
1700 wined3d_texture_invalidate_location(texture, i,
1701 WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB);
1705 /* Context activation is done by the caller. */
1706 void wined3d_texture_prepare_texture(struct wined3d_texture *texture, struct wined3d_context *context, BOOL srgb)
1708 DWORD alloc_flag = srgb ? WINED3D_TEXTURE_SRGB_ALLOCATED : WINED3D_TEXTURE_RGB_ALLOCATED;
1709 const struct wined3d_format *format = texture->resource.format;
1710 const struct wined3d_d3d_info *d3d_info = context->d3d_info;
1711 const struct wined3d_gl_info *gl_info = context->gl_info;
1712 const struct wined3d_color_key_conversion *conversion;
1713 GLenum internal;
1715 TRACE("texture %p, context %p, format %s.\n", texture, context, debug_d3dformat(format->id));
1717 if (!d3d_info->shader_color_key
1718 && !(texture->async.flags & WINED3D_TEXTURE_ASYNC_COLOR_KEY)
1719 != !(texture->async.color_key_flags & WINED3D_CKEY_SRC_BLT))
1721 wined3d_texture_force_reload(texture);
1723 if (texture->async.color_key_flags & WINED3D_CKEY_SRC_BLT)
1724 texture->async.flags |= WINED3D_TEXTURE_ASYNC_COLOR_KEY;
1727 if (texture->flags & alloc_flag)
1728 return;
1730 if (texture->resource.format_flags & WINED3DFMT_FLAG_DECOMPRESS)
1732 TRACE("WINED3DFMT_FLAG_DECOMPRESS set.\n");
1733 texture->flags |= WINED3D_TEXTURE_CONVERTED;
1734 format = wined3d_resource_get_decompress_format(&texture->resource, context);
1736 else if (format->conv_byte_count)
1738 texture->flags |= WINED3D_TEXTURE_CONVERTED;
1740 else if ((conversion = wined3d_format_get_color_key_conversion(texture, TRUE)))
1742 texture->flags |= WINED3D_TEXTURE_CONVERTED;
1743 format = wined3d_get_format(gl_info, conversion->dst_format, texture->resource.usage);
1744 TRACE("Using format %s for color key conversion.\n", debug_d3dformat(format->id));
1747 wined3d_texture_bind_and_dirtify(texture, context, srgb);
1749 if (srgb)
1750 internal = format->glGammaInternal;
1751 else if (texture->resource.usage & WINED3DUSAGE_RENDERTARGET
1752 && wined3d_resource_is_offscreen(&texture->resource))
1753 internal = format->rtInternal;
1754 else
1755 internal = format->glInternal;
1757 if (!internal)
1758 FIXME("No GL internal format for format %s.\n", debug_d3dformat(format->id));
1760 TRACE("internal %#x, format %#x, type %#x.\n", internal, format->glFormat, format->glType);
1762 if (wined3d_texture_use_immutable_storage(texture, gl_info))
1763 wined3d_texture_allocate_gl_immutable_storage(texture, internal, gl_info);
1764 else
1765 wined3d_texture_allocate_gl_mutable_storage(texture, internal, format, gl_info);
1766 texture->flags |= alloc_flag;
1769 static void wined3d_texture_prepare_rb(struct wined3d_texture *texture,
1770 const struct wined3d_gl_info *gl_info, BOOL multisample)
1772 const struct wined3d_format *format = texture->resource.format;
1774 if (multisample)
1776 DWORD samples;
1778 if (texture->rb_multisample)
1779 return;
1781 samples = wined3d_texture_get_gl_sample_count(texture);
1783 gl_info->fbo_ops.glGenRenderbuffers(1, &texture->rb_multisample);
1784 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, texture->rb_multisample);
1785 gl_info->fbo_ops.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,
1786 format->glInternal, texture->resource.width, texture->resource.height);
1787 checkGLcall("glRenderbufferStorageMultisample()");
1788 TRACE("Created multisample rb %u.\n", texture->rb_multisample);
1790 else
1792 if (texture->rb_resolved)
1793 return;
1795 gl_info->fbo_ops.glGenRenderbuffers(1, &texture->rb_resolved);
1796 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, texture->rb_resolved);
1797 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER, format->glInternal,
1798 texture->resource.width, texture->resource.height);
1799 checkGLcall("glRenderbufferStorage()");
1800 TRACE("Created resolved rb %u.\n", texture->rb_resolved);
1804 /* Context activation is done by the caller. Context may be NULL in
1805 * WINED3D_NO3D mode. */
1806 BOOL wined3d_texture_prepare_location(struct wined3d_texture *texture, unsigned int sub_resource_idx,
1807 struct wined3d_context *context, DWORD location)
1809 switch (location)
1811 case WINED3D_LOCATION_SYSMEM:
1812 if (texture->resource.heap_memory)
1813 return TRUE;
1815 if (!wined3d_resource_allocate_sysmem(&texture->resource))
1816 return FALSE;
1817 return TRUE;
1819 case WINED3D_LOCATION_USER_MEMORY:
1820 if (!texture->user_memory)
1821 ERR("Map binding is set to WINED3D_LOCATION_USER_MEMORY but surface->user_memory is NULL.\n");
1822 return TRUE;
1824 case WINED3D_LOCATION_BUFFER:
1825 wined3d_texture_prepare_buffer_object(texture, sub_resource_idx, context->gl_info);
1826 return TRUE;
1828 case WINED3D_LOCATION_TEXTURE_RGB:
1829 wined3d_texture_prepare_texture(texture, context, FALSE);
1830 return TRUE;
1832 case WINED3D_LOCATION_TEXTURE_SRGB:
1833 wined3d_texture_prepare_texture(texture, context, TRUE);
1834 return TRUE;
1836 case WINED3D_LOCATION_DRAWABLE:
1837 if (!texture->swapchain && wined3d_settings.offscreen_rendering_mode != ORM_BACKBUFFER)
1838 ERR("Texture %p does not have a drawable.\n", texture);
1839 return TRUE;
1841 case WINED3D_LOCATION_RB_MULTISAMPLE:
1842 wined3d_texture_prepare_rb(texture, context->gl_info, TRUE);
1843 return TRUE;
1845 case WINED3D_LOCATION_RB_RESOLVED:
1846 wined3d_texture_prepare_rb(texture, context->gl_info, FALSE);
1847 return TRUE;
1849 default:
1850 ERR("Invalid location %s.\n", wined3d_debug_location(location));
1851 return FALSE;
1855 static struct wined3d_texture_sub_resource *wined3d_texture_get_sub_resource(struct wined3d_texture *texture,
1856 unsigned int sub_resource_idx)
1858 UINT sub_count = texture->level_count * texture->layer_count;
1860 TRACE("texture %p, sub_resource_idx %u.\n", texture, sub_resource_idx);
1862 if (sub_resource_idx >= sub_count)
1864 WARN("sub_resource_idx %u >= sub_count %u.\n", sub_resource_idx, sub_count);
1865 return NULL;
1868 return &texture->sub_resources[sub_resource_idx];
1871 HRESULT CDECL wined3d_texture_add_dirty_region(struct wined3d_texture *texture,
1872 UINT layer, const struct wined3d_box *dirty_region)
1874 TRACE("texture %p, layer %u, dirty_region %s.\n", texture, layer, debug_box(dirty_region));
1876 if (layer >= texture->layer_count)
1878 WARN("Invalid layer %u specified.\n", layer);
1879 return WINED3DERR_INVALIDCALL;
1882 if (dirty_region)
1883 FIXME("Ignoring dirty_region %s.\n", debug_box(dirty_region));
1885 wined3d_cs_emit_add_dirty_texture_region(texture->resource.device->cs, texture, layer);
1887 return WINED3D_OK;
1890 /* This call just uploads data, the caller is responsible for binding the
1891 * correct texture. */
1892 /* Context activation is done by the caller. */
1893 void wined3d_texture_upload_data(struct wined3d_texture *texture, unsigned int sub_resource_idx,
1894 struct wined3d_context *context, const struct wined3d_format *format, const struct wined3d_box *src_box,
1895 const struct wined3d_const_bo_address *data, unsigned int src_row_pitch, unsigned int src_slice_pitch,
1896 unsigned int dst_x, unsigned int dst_y, unsigned int dst_z, BOOL srgb)
1898 const struct wined3d_gl_info *gl_info = context->gl_info;
1899 unsigned int update_w = src_box->right - src_box->left;
1900 unsigned int update_h = src_box->bottom - src_box->top;
1901 unsigned int update_d = src_box->back - src_box->front;
1902 struct wined3d_bo_address bo;
1903 void *converted_mem = NULL;
1904 struct wined3d_format f;
1905 unsigned int level;
1906 BOOL decompress;
1907 GLenum target;
1909 TRACE("texture %p, sub_resource_idx %u, context %p, format %s, src_box %s, data {%#x:%p}, "
1910 "src_row_pitch %#x, src_slice_pitch %#x, dst_x %u, dst_y %u, dst_z %u, srgb %#x.\n",
1911 texture, sub_resource_idx, context, debug_d3dformat(format->id), debug_box(src_box),
1912 data->buffer_object, data->addr, src_row_pitch, src_slice_pitch, dst_x, dst_y, dst_z, srgb);
1914 if (texture->sub_resources[sub_resource_idx].map_count)
1916 WARN("Uploading a texture that is currently mapped, setting WINED3D_TEXTURE_PIN_SYSMEM.\n");
1917 texture->flags |= WINED3D_TEXTURE_PIN_SYSMEM;
1920 if (format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_HEIGHT_SCALE)
1922 update_h *= format->height_scale.numerator;
1923 update_h /= format->height_scale.denominator;
1926 target = wined3d_texture_get_sub_resource_target(texture, sub_resource_idx);
1927 level = sub_resource_idx % texture->level_count;
1929 switch (target)
1931 case GL_TEXTURE_1D_ARRAY:
1932 dst_y = sub_resource_idx / texture->level_count;
1933 update_h = 1;
1934 break;
1935 case GL_TEXTURE_2D_ARRAY:
1936 dst_z = sub_resource_idx / texture->level_count;
1937 update_d = 1;
1938 break;
1939 case GL_TEXTURE_2D_MULTISAMPLE:
1940 case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
1941 FIXME("Not supported for multisample textures.\n");
1942 return;
1945 bo.buffer_object = data->buffer_object;
1946 bo.addr = (BYTE *)data->addr + src_box->front * src_slice_pitch;
1947 if (texture->resource.format_flags & WINED3DFMT_FLAG_BLOCKS)
1949 bo.addr += (src_box->top / format->block_height) * src_row_pitch;
1950 bo.addr += (src_box->left / format->block_width) * format->block_byte_count;
1952 else
1954 bo.addr += src_box->top * src_row_pitch;
1955 bo.addr += src_box->left * format->byte_count;
1958 decompress = texture->resource.format_flags & WINED3DFMT_FLAG_DECOMPRESS;
1959 if (format->upload || decompress)
1961 const struct wined3d_format *compressed_format = format;
1962 unsigned int dst_row_pitch, dst_slice_pitch;
1963 void *src_mem;
1965 if (decompress)
1967 format = wined3d_resource_get_decompress_format(&texture->resource, context);
1969 else
1971 if (texture->resource.format_flags & WINED3DFMT_FLAG_BLOCKS)
1972 ERR("Converting a block-based format.\n");
1974 f = *format;
1975 f.byte_count = format->conv_byte_count;
1976 format = &f;
1979 wined3d_format_calculate_pitch(format, 1, update_w, update_h, &dst_row_pitch, &dst_slice_pitch);
1981 /* Note that uploading 3D textures may require quite some address
1982 * space; it may make sense to upload them per-slice instead. */
1983 if (!(converted_mem = heap_calloc(update_d, dst_slice_pitch)))
1985 ERR("Failed to allocate upload buffer.\n");
1986 return;
1989 src_mem = context_map_bo_address(context, &bo, src_slice_pitch,
1990 GL_PIXEL_UNPACK_BUFFER, WINED3D_MAP_READ);
1991 if (decompress)
1992 compressed_format->decompress(src_mem, converted_mem, src_row_pitch, src_slice_pitch,
1993 dst_row_pitch, dst_slice_pitch, update_w, update_h, update_d);
1994 else
1995 format->upload(src_mem, converted_mem, src_row_pitch, src_slice_pitch,
1996 dst_row_pitch, dst_slice_pitch, update_w, update_h, update_d);
1997 context_unmap_bo_address(context, &bo, GL_PIXEL_UNPACK_BUFFER);
1999 bo.buffer_object = 0;
2000 bo.addr = converted_mem;
2001 src_row_pitch = dst_row_pitch;
2002 src_slice_pitch = dst_slice_pitch;
2005 if (bo.buffer_object)
2007 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, bo.buffer_object));
2008 checkGLcall("glBindBuffer");
2011 if (format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_COMPRESSED)
2013 unsigned int dst_row_pitch, dst_slice_pitch;
2014 const BYTE *addr = bo.addr;
2015 GLenum internal;
2017 if (srgb)
2018 internal = format->glGammaInternal;
2019 else if (texture->resource.usage & WINED3DUSAGE_RENDERTARGET
2020 && wined3d_resource_is_offscreen(&texture->resource))
2021 internal = format->rtInternal;
2022 else
2023 internal = format->glInternal;
2025 wined3d_format_calculate_pitch(format, 1, update_w, update_h, &dst_row_pitch, &dst_slice_pitch);
2027 TRACE("Uploading compressed data, target %#x, level %u, x %u, y %u, z %u, "
2028 "w %u, h %u, d %u, format %#x, image_size %#x, addr %p.\n",
2029 target, level, dst_x, dst_y, dst_z, update_w, update_h,
2030 update_d, internal, dst_slice_pitch, addr);
2032 if (target == GL_TEXTURE_1D)
2034 GL_EXTCALL(glCompressedTexSubImage1D(target, level, dst_x,
2035 update_w, internal, dst_row_pitch, addr));
2037 else if (dst_row_pitch == src_row_pitch)
2039 if (target == GL_TEXTURE_2D_ARRAY || target == GL_TEXTURE_3D)
2041 GL_EXTCALL(glCompressedTexSubImage3D(target, level, dst_x, dst_y, dst_z,
2042 update_w, update_h, update_d, internal, dst_slice_pitch * update_d, addr));
2044 else
2046 GL_EXTCALL(glCompressedTexSubImage2D(target, level, dst_x, dst_y,
2047 update_w, update_h, internal, dst_slice_pitch, addr));
2050 else
2052 unsigned int row_count = (update_h + format->block_height - 1) / format->block_height;
2053 unsigned int row, y, z;
2055 /* glCompressedTexSubImage2D() ignores pixel store state, so we
2056 * can't use the unpack row length like for glTexSubImage2D. */
2057 for (z = dst_z; z < dst_z + update_d; ++z)
2059 for (row = 0, y = dst_y; row < row_count; ++row)
2061 if (target == GL_TEXTURE_2D_ARRAY || target == GL_TEXTURE_3D)
2063 GL_EXTCALL(glCompressedTexSubImage3D(target, level, dst_x, y, z,
2064 update_w, format->block_height, 1, internal, dst_row_pitch, addr));
2066 else
2068 GL_EXTCALL(glCompressedTexSubImage2D(target, level, dst_x, y,
2069 update_w, format->block_height, internal, dst_row_pitch, addr));
2072 y += format->block_height;
2073 addr += src_row_pitch;
2077 checkGLcall("Upload compressed texture data");
2079 else
2081 TRACE("Uploading data, target %#x, level %u, x %u, y %u, z %u, "
2082 "w %u, h %u, d %u, format %#x, type %#x, addr %p.\n",
2083 target, level, dst_x, dst_y, dst_z, update_w, update_h,
2084 update_d, format->glFormat, format->glType, bo.addr);
2086 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, src_row_pitch / format->byte_count);
2087 if (target == GL_TEXTURE_2D_ARRAY || target == GL_TEXTURE_3D)
2089 GL_EXTCALL(glTexSubImage3D(target, level, dst_x, dst_y, dst_z,
2090 update_w, update_h, update_d, format->glFormat, format->glType, bo.addr));
2092 else if (target == GL_TEXTURE_1D)
2094 gl_info->gl_ops.gl.p_glTexSubImage1D(target, level, dst_x,
2095 update_w, format->glFormat, format->glType, bo.addr);
2097 else
2099 gl_info->gl_ops.gl.p_glTexSubImage2D(target, level, dst_x, dst_y,
2100 update_w, update_h, format->glFormat, format->glType, bo.addr);
2102 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
2103 checkGLcall("Upload texture data");
2106 if (bo.buffer_object)
2108 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));
2109 checkGLcall("glBindBuffer");
2111 heap_free(converted_mem);
2113 if (gl_info->quirks & WINED3D_QUIRK_FBO_TEX_UPDATE)
2115 struct wined3d_device *device = texture->resource.device;
2116 unsigned int i;
2118 for (i = 0; i < device->context_count; ++i)
2120 context_texture_update(device->contexts[i], texture);
2125 /* Context activation is done by the caller. Context may be NULL in ddraw-only mode. */
2126 static BOOL texture2d_load_location(struct wined3d_texture *texture, unsigned int sub_resource_idx,
2127 struct wined3d_context *context, DWORD location)
2129 TRACE("texture %p, sub_resource_idx %u, context %p, location %s.\n",
2130 texture, sub_resource_idx, context, wined3d_debug_location(location));
2132 switch (location)
2134 case WINED3D_LOCATION_USER_MEMORY:
2135 case WINED3D_LOCATION_SYSMEM:
2136 case WINED3D_LOCATION_BUFFER:
2137 return texture2d_load_sysmem(texture, sub_resource_idx, context, location);
2139 case WINED3D_LOCATION_DRAWABLE:
2140 return texture2d_load_drawable(texture, sub_resource_idx, context);
2142 case WINED3D_LOCATION_RB_RESOLVED:
2143 case WINED3D_LOCATION_RB_MULTISAMPLE:
2144 return texture2d_load_renderbuffer(texture, sub_resource_idx, context, location);
2146 case WINED3D_LOCATION_TEXTURE_RGB:
2147 case WINED3D_LOCATION_TEXTURE_SRGB:
2148 return texture2d_load_texture(texture, sub_resource_idx, context,
2149 location == WINED3D_LOCATION_TEXTURE_SRGB);
2151 default:
2152 ERR("Don't know how to handle location %#x.\n", location);
2153 return FALSE;
2157 static const struct wined3d_texture_ops texture2d_ops =
2159 texture2d_load_location,
2162 struct wined3d_texture * __cdecl wined3d_texture_from_resource(struct wined3d_resource *resource)
2164 return texture_from_resource(resource);
2167 static ULONG texture_resource_incref(struct wined3d_resource *resource)
2169 return wined3d_texture_incref(texture_from_resource(resource));
2172 static ULONG texture_resource_decref(struct wined3d_resource *resource)
2174 return wined3d_texture_decref(texture_from_resource(resource));
2177 static void texture_resource_preload(struct wined3d_resource *resource)
2179 struct wined3d_texture *texture = texture_from_resource(resource);
2180 struct wined3d_context *context;
2182 context = context_acquire(resource->device, NULL, 0);
2183 wined3d_texture_load(texture, context, texture->flags & WINED3D_TEXTURE_IS_SRGB);
2184 context_release(context);
2187 static void wined3d_texture_unload(struct wined3d_resource *resource)
2189 struct wined3d_texture *texture = texture_from_resource(resource);
2190 UINT sub_count = texture->level_count * texture->layer_count;
2191 struct wined3d_renderbuffer_entry *entry, *entry2;
2192 struct wined3d_device *device = resource->device;
2193 const struct wined3d_gl_info *gl_info;
2194 struct wined3d_context *context;
2195 UINT i;
2197 TRACE("texture %p.\n", texture);
2199 context = context_acquire(device, NULL, 0);
2200 gl_info = context->gl_info;
2202 for (i = 0; i < sub_count; ++i)
2204 struct wined3d_texture_sub_resource *sub_resource = &texture->sub_resources[i];
2206 if (resource->access & WINED3D_RESOURCE_ACCESS_CPU
2207 && wined3d_texture_load_location(texture, i, context, resource->map_binding))
2209 wined3d_texture_invalidate_location(texture, i, ~resource->map_binding);
2211 else
2213 /* We should only get here on device reset/teardown for implicit
2214 * resources. */
2215 if (resource->access & WINED3D_RESOURCE_ACCESS_CPU
2216 || resource->type != WINED3D_RTYPE_TEXTURE_2D)
2217 ERR("Discarding %s %p sub-resource %u with resource access %s.\n",
2218 debug_d3dresourcetype(resource->type), resource, i,
2219 wined3d_debug_resource_access(resource->access));
2220 wined3d_texture_validate_location(texture, i, WINED3D_LOCATION_DISCARDED);
2221 wined3d_texture_invalidate_location(texture, i, ~WINED3D_LOCATION_DISCARDED);
2224 if (sub_resource->buffer_object)
2225 wined3d_texture_remove_buffer_object(texture, i, context->gl_info);
2228 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &texture->renderbuffers, struct wined3d_renderbuffer_entry, entry)
2230 context_gl_resource_released(device, entry->id, TRUE);
2231 gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id);
2232 list_remove(&entry->entry);
2233 heap_free(entry);
2235 list_init(&texture->renderbuffers);
2236 texture->current_renderbuffer = NULL;
2238 context_release(context);
2240 wined3d_texture_force_reload(texture);
2241 wined3d_texture_unload_gl_texture(texture);
2244 static HRESULT texture_resource_sub_resource_map(struct wined3d_resource *resource, unsigned int sub_resource_idx,
2245 struct wined3d_map_desc *map_desc, const struct wined3d_box *box, DWORD flags)
2247 const struct wined3d_format *format = resource->format;
2248 struct wined3d_texture_sub_resource *sub_resource;
2249 struct wined3d_device *device = resource->device;
2250 unsigned int fmt_flags = resource->format_flags;
2251 struct wined3d_context *context = NULL;
2252 struct wined3d_texture *texture;
2253 struct wined3d_bo_address data;
2254 unsigned int texture_level;
2255 BYTE *base_memory;
2256 BOOL ret;
2258 TRACE("resource %p, sub_resource_idx %u, map_desc %p, box %s, flags %#x.\n",
2259 resource, sub_resource_idx, map_desc, debug_box(box), flags);
2261 texture = texture_from_resource(resource);
2262 if (!(sub_resource = wined3d_texture_get_sub_resource(texture, sub_resource_idx)))
2263 return E_INVALIDARG;
2265 texture_level = sub_resource_idx % texture->level_count;
2266 if (box && FAILED(wined3d_texture_check_box_dimensions(texture, texture_level, box)))
2268 WARN("Map box is invalid.\n");
2269 if (((fmt_flags & WINED3DFMT_FLAG_BLOCKS) && !(resource->access & WINED3D_RESOURCE_ACCESS_CPU))
2270 || resource->type != WINED3D_RTYPE_TEXTURE_2D)
2271 return WINED3DERR_INVALIDCALL;
2274 if (texture->flags & WINED3D_TEXTURE_DC_IN_USE)
2276 WARN("DC is in use.\n");
2277 return WINED3DERR_INVALIDCALL;
2280 if (sub_resource->map_count)
2282 WARN("Sub-resource is already mapped.\n");
2283 return WINED3DERR_INVALIDCALL;
2286 if (device->d3d_initialized)
2287 context = context_acquire(device, NULL, 0);
2289 if (flags & WINED3D_MAP_DISCARD)
2291 TRACE("WINED3D_MAP_DISCARD flag passed, marking %s as up to date.\n",
2292 wined3d_debug_location(resource->map_binding));
2293 if ((ret = wined3d_texture_prepare_location(texture, sub_resource_idx, context, resource->map_binding)))
2294 wined3d_texture_validate_location(texture, sub_resource_idx, resource->map_binding);
2296 else
2298 if (resource->usage & WINED3DUSAGE_DYNAMIC)
2299 WARN_(d3d_perf)("Mapping a dynamic texture without WINED3D_MAP_DISCARD.\n");
2300 ret = wined3d_texture_load_location(texture, sub_resource_idx, context, resource->map_binding);
2303 if (!ret)
2305 ERR("Failed to prepare location.\n");
2306 context_release(context);
2307 return E_OUTOFMEMORY;
2310 if (flags & WINED3D_MAP_WRITE
2311 && (!(flags & WINED3D_MAP_NO_DIRTY_UPDATE) || (resource->usage & WINED3DUSAGE_DYNAMIC)))
2312 wined3d_texture_invalidate_location(texture, sub_resource_idx, ~resource->map_binding);
2314 wined3d_texture_get_memory(texture, sub_resource_idx, &data, resource->map_binding);
2315 base_memory = context_map_bo_address(context, &data, sub_resource->size, GL_PIXEL_UNPACK_BUFFER, flags);
2316 TRACE("Base memory pointer %p.\n", base_memory);
2318 if (context)
2319 context_release(context);
2321 if (fmt_flags & WINED3DFMT_FLAG_BROKEN_PITCH)
2323 map_desc->row_pitch = wined3d_texture_get_level_width(texture, texture_level) * format->byte_count;
2324 map_desc->slice_pitch = wined3d_texture_get_level_height(texture, texture_level) * map_desc->row_pitch;
2326 else
2328 wined3d_texture_get_pitch(texture, texture_level, &map_desc->row_pitch, &map_desc->slice_pitch);
2331 if (!box)
2333 map_desc->data = base_memory;
2335 else
2337 if ((fmt_flags & (WINED3DFMT_FLAG_BLOCKS | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_BLOCKS)
2339 /* Compressed textures are block based, so calculate the offset of
2340 * the block that contains the top-left pixel of the mapped box. */
2341 map_desc->data = base_memory
2342 + (box->front * map_desc->slice_pitch)
2343 + ((box->top / format->block_height) * map_desc->row_pitch)
2344 + ((box->left / format->block_width) * format->block_byte_count);
2346 else
2348 map_desc->data = base_memory
2349 + (box->front * map_desc->slice_pitch)
2350 + (box->top * map_desc->row_pitch)
2351 + (box->left * format->byte_count);
2355 if (texture->swapchain && texture->swapchain->front_buffer == texture)
2357 RECT *r = &texture->swapchain->front_buffer_update;
2359 if (!box)
2360 SetRect(r, 0, 0, resource->width, resource->height);
2361 else
2362 SetRect(r, box->left, box->top, box->right, box->bottom);
2363 TRACE("Mapped front buffer %s.\n", wine_dbgstr_rect(r));
2366 ++resource->map_count;
2367 ++sub_resource->map_count;
2369 TRACE("Returning memory %p, row pitch %u, slice pitch %u.\n",
2370 map_desc->data, map_desc->row_pitch, map_desc->slice_pitch);
2372 return WINED3D_OK;
2375 static HRESULT texture_resource_sub_resource_unmap(struct wined3d_resource *resource, unsigned int sub_resource_idx)
2377 struct wined3d_texture_sub_resource *sub_resource;
2378 struct wined3d_device *device = resource->device;
2379 struct wined3d_context *context = NULL;
2380 struct wined3d_texture *texture;
2381 struct wined3d_bo_address data;
2383 TRACE("resource %p, sub_resource_idx %u.\n", resource, sub_resource_idx);
2385 texture = texture_from_resource(resource);
2386 if (!(sub_resource = wined3d_texture_get_sub_resource(texture, sub_resource_idx)))
2387 return E_INVALIDARG;
2389 if (!sub_resource->map_count)
2391 WARN("Trying to unmap unmapped sub-resource.\n");
2392 if (texture->flags & WINED3D_TEXTURE_DC_IN_USE)
2393 return WINED3D_OK;
2394 return WINEDDERR_NOTLOCKED;
2397 if (device->d3d_initialized)
2398 context = context_acquire(device, NULL, 0);
2400 wined3d_texture_get_memory(texture, sub_resource_idx, &data, texture->resource.map_binding);
2401 context_unmap_bo_address(context, &data, GL_PIXEL_UNPACK_BUFFER);
2403 if (context)
2404 context_release(context);
2406 if (texture->swapchain && texture->swapchain->front_buffer == texture)
2408 if (!(sub_resource->locations & (WINED3D_LOCATION_DRAWABLE | WINED3D_LOCATION_TEXTURE_RGB)))
2409 texture->swapchain->swapchain_ops->swapchain_frontbuffer_updated(texture->swapchain);
2412 --sub_resource->map_count;
2413 if (!--resource->map_count && texture->update_map_binding)
2414 wined3d_texture_update_map_binding(texture);
2416 return WINED3D_OK;
2419 static const struct wined3d_resource_ops texture_resource_ops =
2421 texture_resource_incref,
2422 texture_resource_decref,
2423 texture_resource_preload,
2424 wined3d_texture_unload,
2425 texture_resource_sub_resource_map,
2426 texture_resource_sub_resource_unmap,
2429 /* Context activation is done by the caller. */
2430 static void texture1d_download_data(struct wined3d_texture *texture, unsigned int sub_resource_idx,
2431 const struct wined3d_context *context, const struct wined3d_bo_address *data)
2433 const struct wined3d_format *format = texture->resource.format;
2434 const struct wined3d_gl_info *gl_info = context->gl_info;
2436 if (format->conv_byte_count)
2438 FIXME("Attempting to download a converted texture, format %s.\n",
2439 debug_d3dformat(format->id));
2440 return;
2443 if (data->buffer_object)
2445 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, data->buffer_object));
2446 checkGLcall("glBindBuffer");
2449 gl_info->gl_ops.gl.p_glGetTexImage(texture->target, sub_resource_idx,
2450 format->glFormat, format->glType, data->addr);
2451 checkGLcall("glGetTexImage");
2453 if (data->buffer_object)
2455 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
2456 checkGLcall("glBindBuffer");
2460 /* Context activation is done by the caller. */
2461 static BOOL texture1d_load_location(struct wined3d_texture *texture, unsigned int sub_resource_idx,
2462 struct wined3d_context *context, DWORD location)
2464 struct wined3d_texture_sub_resource *sub_resource = &texture->sub_resources[sub_resource_idx];
2465 unsigned int row_pitch, slice_pitch;
2467 TRACE("texture %p, sub_resource_idx %u, context %p, location %s.\n",
2468 texture, sub_resource_idx, context, wined3d_debug_location(location));
2470 if (!wined3d_texture_prepare_location(texture, sub_resource_idx, context, location))
2471 return FALSE;
2473 switch (location)
2475 case WINED3D_LOCATION_TEXTURE_RGB:
2476 case WINED3D_LOCATION_TEXTURE_SRGB:
2477 if (sub_resource->locations & WINED3D_LOCATION_SYSMEM)
2479 struct wined3d_const_bo_address data = {0, texture->resource.heap_memory};
2480 struct wined3d_box src_box;
2482 data.addr += sub_resource->offset;
2483 wined3d_texture_bind_and_dirtify(texture, context,
2484 location == WINED3D_LOCATION_TEXTURE_SRGB);
2485 wined3d_texture_get_pitch(texture, sub_resource_idx, &row_pitch, &slice_pitch);
2486 wined3d_texture_get_level_box(texture, sub_resource_idx % texture->level_count, &src_box);
2487 wined3d_texture_upload_data(texture, sub_resource_idx, context, texture->resource.format,
2488 &src_box, &data, row_pitch, slice_pitch, 0, 0, 0, FALSE);
2490 else if (sub_resource->locations & WINED3D_LOCATION_BUFFER)
2492 struct wined3d_const_bo_address data = {sub_resource->buffer_object, NULL};
2493 struct wined3d_box src_box;
2495 wined3d_texture_bind_and_dirtify(texture, context,
2496 location == WINED3D_LOCATION_TEXTURE_SRGB);
2497 wined3d_texture_get_pitch(texture, sub_resource_idx, &row_pitch, &slice_pitch);
2498 wined3d_texture_get_level_box(texture, sub_resource_idx % texture->level_count, &src_box);
2499 wined3d_texture_upload_data(texture, sub_resource_idx, context, texture->resource.format,
2500 &src_box, &data, row_pitch, slice_pitch, 0, 0, 0, FALSE);
2502 else
2504 FIXME("Implement texture loading from %s.\n", wined3d_debug_location(sub_resource->locations));
2505 return FALSE;
2507 break;
2509 case WINED3D_LOCATION_SYSMEM:
2510 if (sub_resource->locations & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB))
2512 struct wined3d_bo_address data = {0, texture->resource.heap_memory};
2514 data.addr += sub_resource->offset;
2515 if (sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB)
2516 wined3d_texture_bind_and_dirtify(texture, context, FALSE);
2517 else
2518 wined3d_texture_bind_and_dirtify(texture, context, TRUE);
2520 texture1d_download_data(texture, sub_resource_idx, context, &data);
2521 ++texture->download_count;
2523 else
2525 FIXME("Implement WINED3D_LOCATION_SYSMEM loading from %s.\n",
2526 wined3d_debug_location(sub_resource->locations));
2527 return FALSE;
2529 break;
2531 case WINED3D_LOCATION_BUFFER:
2532 if (sub_resource->locations & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB))
2534 struct wined3d_bo_address data = {sub_resource->buffer_object, NULL};
2536 if (sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB)
2537 wined3d_texture_bind_and_dirtify(texture, context, FALSE);
2538 else
2539 wined3d_texture_bind_and_dirtify(texture, context, TRUE);
2541 texture1d_download_data(texture, sub_resource_idx, context, &data);
2543 else
2545 FIXME("Implement WINED3D_LOCATION_BUFFER loading from %s.\n",
2546 wined3d_debug_location(sub_resource->locations));
2547 return FALSE;
2549 break;
2551 default:
2552 FIXME("Implement %s loading from %s.\n", wined3d_debug_location(location),
2553 wined3d_debug_location(sub_resource->locations));
2554 return FALSE;
2557 return TRUE;
2560 static const struct wined3d_texture_ops texture1d_ops =
2562 texture1d_load_location,
2565 static HRESULT wined3d_texture_init(struct wined3d_texture *texture, const struct wined3d_resource_desc *desc,
2566 unsigned int layer_count, unsigned int level_count, DWORD flags, struct wined3d_device *device,
2567 void *parent, const struct wined3d_parent_ops *parent_ops, const struct wined3d_texture_ops *texture_ops)
2569 struct wined3d_device_parent *device_parent = device->device_parent;
2570 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
2571 unsigned int sub_count, i, j, size, offset = 0;
2572 unsigned int pow2_width, pow2_height;
2573 const struct wined3d_format *format;
2574 HRESULT hr;
2576 TRACE("texture %p, resource_type %s, format %s, multisample_type %#x, multisample_quality %#x, "
2577 "usage %s, access %s, width %u, height %u, depth %u, layer_count %u, level_count %u, "
2578 "flags %#x, device %p, parent %p, parent_ops %p, texture_ops %p.\n",
2579 texture, debug_d3dresourcetype(desc->resource_type), debug_d3dformat(desc->format),
2580 desc->multisample_type, desc->multisample_quality, debug_d3dusage(desc->usage),
2581 wined3d_debug_resource_access(desc->access), desc->width, desc->height, desc->depth,
2582 layer_count, level_count, flags, device, parent, parent_ops, texture_ops);
2584 if (!desc->width || !desc->height || !desc->depth)
2585 return WINED3DERR_INVALIDCALL;
2587 if (desc->resource_type == WINED3D_RTYPE_TEXTURE_3D)
2589 if (layer_count != 1)
2591 ERR("Invalid layer count for volume texture.\n");
2592 return E_INVALIDARG;
2595 if (!gl_info->supported[EXT_TEXTURE3D])
2597 WARN("OpenGL implementation does not support 3D textures.\n");
2598 return WINED3DERR_INVALIDCALL;
2602 if (!(desc->usage & WINED3DUSAGE_LEGACY_CUBEMAP) && layer_count > 1
2603 && !gl_info->supported[EXT_TEXTURE_ARRAY])
2605 WARN("OpenGL implementation does not support array textures.\n");
2606 return WINED3DERR_INVALIDCALL;
2609 /* TODO: It should only be possible to create textures for formats
2610 * that are reported as supported. */
2611 if (WINED3DFMT_UNKNOWN >= desc->format)
2613 WARN("Texture cannot be created with a format of WINED3DFMT_UNKNOWN.\n");
2614 return WINED3DERR_INVALIDCALL;
2617 if (desc->usage & WINED3DUSAGE_DYNAMIC && (wined3d_resource_access_is_managed(desc->access)
2618 || desc->usage & WINED3DUSAGE_SCRATCH))
2620 WARN("Attempted to create a dynamic texture with access %s and usage %s.\n",
2621 wined3d_debug_resource_access(desc->access), debug_d3dusage(desc->usage));
2622 return WINED3DERR_INVALIDCALL;
2625 if (!(desc->usage & (WINED3DUSAGE_DYNAMIC | WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL))
2626 && (flags & WINED3D_TEXTURE_CREATE_MAPPABLE))
2627 WARN("Creating a mappable texture that doesn't specify dynamic usage.\n");
2628 if (desc->usage & WINED3DUSAGE_RENDERTARGET && desc->access & WINED3D_RESOURCE_ACCESS_CPU)
2629 FIXME("Trying to create a CPU accessible render target.\n");
2631 pow2_width = desc->width;
2632 pow2_height = desc->height;
2633 if (((desc->width & (desc->width - 1)) || (desc->height & (desc->height - 1)) || (desc->depth & (desc->depth - 1)))
2634 && !gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO])
2636 /* level_count == 0 returns an error as well. */
2637 if (level_count != 1 || layer_count != 1 || desc->resource_type == WINED3D_RTYPE_TEXTURE_3D)
2639 if (!(desc->usage & WINED3DUSAGE_SCRATCH))
2641 WARN("Attempted to create a mipmapped/cube/array/volume NPOT "
2642 "texture without unconditional NPOT support.\n");
2643 return WINED3DERR_INVALIDCALL;
2646 WARN("Creating a scratch mipmapped/cube/array NPOT texture despite lack of HW support.\n");
2648 texture->flags |= WINED3D_TEXTURE_COND_NP2;
2650 if (desc->resource_type != WINED3D_RTYPE_TEXTURE_3D && !gl_info->supported[ARB_TEXTURE_RECTANGLE]
2651 && !gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
2653 const struct wined3d_format *format = wined3d_get_format(gl_info, desc->format, desc->usage);
2655 /* TODO: Add support for non-power-of-two compressed textures. */
2656 if (format->flags[WINED3D_GL_RES_TYPE_TEX_2D]
2657 & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_HEIGHT_SCALE))
2659 FIXME("Compressed or height scaled non-power-of-two (%ux%u) textures are not supported.\n",
2660 desc->width, desc->height);
2661 return WINED3DERR_NOTAVAILABLE;
2664 /* Find the nearest pow2 match. */
2665 pow2_width = pow2_height = 1;
2666 while (pow2_width < desc->width)
2667 pow2_width <<= 1;
2668 while (pow2_height < desc->height)
2669 pow2_height <<= 1;
2670 texture->flags |= WINED3D_TEXTURE_COND_NP2_EMULATED;
2673 texture->pow2_width = pow2_width;
2674 texture->pow2_height = pow2_height;
2676 if ((pow2_width > gl_info->limits.texture_size || pow2_height > gl_info->limits.texture_size)
2677 && (desc->usage & WINED3DUSAGE_TEXTURE))
2679 /* One of four options:
2680 * 1: Do the same as we do with NPOT and scale the texture. (Any
2681 * texture ops would require the texture to be scaled which is
2682 * potentially slow.)
2683 * 2: Set the texture to the maximum size (bad idea).
2684 * 3: WARN and return WINED3DERR_NOTAVAILABLE.
2685 * 4: Create the surface, but allow it to be used only for DirectDraw
2686 * Blts. Some apps (e.g. Swat 3) create textures with a height of
2687 * 16 and a width > 3000 and blt 16x16 letter areas from them to
2688 * the render target. */
2689 if (desc->access & WINED3D_RESOURCE_ACCESS_GPU)
2691 WARN("Dimensions (%ux%u) exceed the maximum texture size.\n", pow2_width, pow2_height);
2692 return WINED3DERR_NOTAVAILABLE;
2695 /* We should never use this surface in combination with OpenGL. */
2696 TRACE("Creating an oversized (%ux%u) surface.\n", pow2_width, pow2_height);
2699 format = wined3d_get_format(&device->adapter->gl_info, desc->format, desc->usage);
2700 for (i = 0; i < layer_count; ++i)
2702 for (j = 0; j < level_count; ++j)
2704 unsigned int idx = i * level_count + j;
2706 size = wined3d_format_calculate_size(format, device->surface_alignment,
2707 max(1, desc->width >> j), max(1, desc->height >> j), max(1, desc->depth >> j));
2708 texture->sub_resources[idx].offset = offset;
2709 texture->sub_resources[idx].size = size;
2710 offset += size;
2712 offset = (offset + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1);
2715 if (!offset)
2716 return WINED3DERR_INVALIDCALL;
2718 if (FAILED(hr = resource_init(&texture->resource, device, desc->resource_type, format,
2719 desc->multisample_type, desc->multisample_quality, desc->usage, desc->access,
2720 desc->width, desc->height, desc->depth, offset, parent, parent_ops, &texture_resource_ops)))
2722 static unsigned int once;
2724 /* DXTn 3D textures are not supported. Do not write the ERR for them. */
2725 if ((desc->format == WINED3DFMT_DXT1 || desc->format == WINED3DFMT_DXT2 || desc->format == WINED3DFMT_DXT3
2726 || desc->format == WINED3DFMT_DXT4 || desc->format == WINED3DFMT_DXT5)
2727 && !(format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_TEXTURE)
2728 && desc->resource_type != WINED3D_RTYPE_TEXTURE_3D && !once++)
2729 ERR_(winediag)("The application tried to create a DXTn texture, but the driver does not support them.\n");
2731 WARN("Failed to initialize resource, returning %#x\n", hr);
2732 return hr;
2734 wined3d_resource_update_draw_binding(&texture->resource);
2735 if ((flags & WINED3D_TEXTURE_CREATE_MAPPABLE) || desc->format == WINED3DFMT_D16_LOCKABLE)
2736 texture->resource.access |= WINED3D_RESOURCE_ACCESS_MAP_R | WINED3D_RESOURCE_ACCESS_MAP_W;
2738 texture->texture_ops = texture_ops;
2740 texture->layer_count = layer_count;
2741 texture->level_count = level_count;
2742 texture->lod = 0;
2743 texture->flags |= WINED3D_TEXTURE_POW2_MAT_IDENT | WINED3D_TEXTURE_NORMALIZED_COORDS;
2744 if (flags & WINED3D_TEXTURE_CREATE_GET_DC_LENIENT)
2745 texture->flags |= WINED3D_TEXTURE_PIN_SYSMEM | WINED3D_TEXTURE_GET_DC_LENIENT;
2746 if (flags & (WINED3D_TEXTURE_CREATE_GET_DC | WINED3D_TEXTURE_CREATE_GET_DC_LENIENT))
2747 texture->flags |= WINED3D_TEXTURE_GET_DC;
2748 if (flags & WINED3D_TEXTURE_CREATE_DISCARD)
2749 texture->flags |= WINED3D_TEXTURE_DISCARD;
2750 if (flags & WINED3D_TEXTURE_CREATE_GENERATE_MIPMAPS)
2752 if (!(texture->resource.format_flags & WINED3DFMT_FLAG_GEN_MIPMAP))
2753 WARN("Format doesn't support mipmaps generation, "
2754 "ignoring WINED3D_TEXTURE_CREATE_GENERATE_MIPMAPS flag.\n");
2755 else
2756 texture->flags |= WINED3D_TEXTURE_GENERATE_MIPMAPS;
2759 list_init(&texture->renderbuffers);
2761 switch (desc->resource_type)
2763 case WINED3D_RTYPE_TEXTURE_1D:
2764 if (layer_count > 1)
2765 texture->target = GL_TEXTURE_1D_ARRAY;
2766 else
2767 texture->target = GL_TEXTURE_1D;
2768 break;
2770 case WINED3D_RTYPE_TEXTURE_2D:
2771 if (desc->usage & WINED3DUSAGE_LEGACY_CUBEMAP)
2773 texture->target = GL_TEXTURE_CUBE_MAP_ARB;
2775 else if (desc->multisample_type && gl_info->supported[ARB_TEXTURE_MULTISAMPLE])
2777 if (layer_count > 1)
2778 texture->target = GL_TEXTURE_2D_MULTISAMPLE_ARRAY;
2779 else
2780 texture->target = GL_TEXTURE_2D_MULTISAMPLE;
2782 else
2784 if (layer_count > 1)
2785 texture->target = GL_TEXTURE_2D_ARRAY;
2786 else
2787 texture->target = GL_TEXTURE_2D;
2789 break;
2791 case WINED3D_RTYPE_TEXTURE_3D:
2792 texture->target = GL_TEXTURE_3D;
2793 break;
2795 default:
2796 ERR("Invalid resource type %s.\n", debug_d3dresourcetype(desc->resource_type));
2797 wined3d_texture_cleanup_sync(texture);
2798 return WINED3DERR_INVALIDCALL;
2801 /* Precalculated scaling for 'faked' non power of two texture coords. */
2802 if (texture->resource.gl_type == WINED3D_GL_RES_TYPE_TEX_RECT)
2804 texture->pow2_matrix[0] = (float)desc->width;
2805 texture->pow2_matrix[5] = (float)desc->height;
2806 texture->flags &= ~(WINED3D_TEXTURE_POW2_MAT_IDENT | WINED3D_TEXTURE_NORMALIZED_COORDS);
2807 texture->target = GL_TEXTURE_RECTANGLE_ARB;
2809 else if (texture->flags & WINED3D_TEXTURE_COND_NP2_EMULATED)
2811 texture->pow2_matrix[0] = (((float)desc->width) / ((float)pow2_width));
2812 texture->pow2_matrix[5] = (((float)desc->height) / ((float)pow2_height));
2813 texture->flags &= ~WINED3D_TEXTURE_POW2_MAT_IDENT;
2815 else
2817 texture->pow2_matrix[0] = 1.0f;
2818 texture->pow2_matrix[5] = 1.0f;
2820 texture->pow2_matrix[10] = 1.0f;
2821 texture->pow2_matrix[15] = 1.0f;
2822 TRACE("x scale %.8e, y scale %.8e.\n", texture->pow2_matrix[0], texture->pow2_matrix[5]);
2824 if (wined3d_texture_use_pbo(texture, gl_info))
2825 texture->resource.map_binding = WINED3D_LOCATION_BUFFER;
2827 if (desc->resource_type != WINED3D_RTYPE_TEXTURE_3D
2828 || !wined3d_texture_use_pbo(texture, gl_info))
2830 if (!wined3d_resource_allocate_sysmem(&texture->resource))
2832 wined3d_texture_cleanup_sync(texture);
2833 return E_OUTOFMEMORY;
2837 sub_count = level_count * layer_count;
2838 if (sub_count / layer_count != level_count)
2840 wined3d_texture_cleanup_sync(texture);
2841 return E_OUTOFMEMORY;
2844 if (desc->usage & WINED3DUSAGE_OVERLAY)
2846 if (!(texture->overlay_info = heap_calloc(sub_count, sizeof(*texture->overlay_info))))
2848 wined3d_texture_cleanup_sync(texture);
2849 return E_OUTOFMEMORY;
2852 for (i = 0; i < sub_count; ++i)
2854 list_init(&texture->overlay_info[i].entry);
2855 list_init(&texture->overlay_info[i].overlays);
2859 /* Generate all sub-resources. */
2860 for (i = 0; i < sub_count; ++i)
2862 struct wined3d_texture_sub_resource *sub_resource;
2864 sub_resource = &texture->sub_resources[i];
2865 sub_resource->locations = WINED3D_LOCATION_DISCARDED;
2866 if (desc->resource_type != WINED3D_RTYPE_TEXTURE_3D)
2868 wined3d_texture_validate_location(texture, i, WINED3D_LOCATION_SYSMEM);
2869 wined3d_texture_invalidate_location(texture, i, ~WINED3D_LOCATION_SYSMEM);
2872 if (FAILED(hr = device_parent->ops->texture_sub_resource_created(device_parent,
2873 desc->resource_type, texture, i, &sub_resource->parent, &sub_resource->parent_ops)))
2875 WARN("Failed to create sub-resource parent, hr %#x.\n", hr);
2876 sub_resource->parent = NULL;
2877 wined3d_texture_cleanup_sync(texture);
2878 return hr;
2881 TRACE("parent %p, parent_ops %p.\n", sub_resource->parent, sub_resource->parent_ops);
2883 TRACE("Created sub-resource %u (level %u, layer %u).\n",
2884 i, i % texture->level_count, i / texture->level_count);
2886 if ((desc->usage & WINED3DUSAGE_OWNDC) || (device->wined3d->flags & WINED3D_NO3D))
2888 struct wined3d_texture_idx texture_idx = {texture, i};
2890 wined3d_cs_init_object(device->cs, wined3d_texture_create_dc, &texture_idx);
2891 device->cs->ops->finish(device->cs, WINED3D_CS_QUEUE_DEFAULT);
2892 if (!texture->dc_info || !texture->dc_info[i].dc)
2894 wined3d_texture_cleanup_sync(texture);
2895 return WINED3DERR_INVALIDCALL;
2900 return WINED3D_OK;
2903 /* Context activation is done by the caller. */
2904 static void texture3d_download_data(struct wined3d_texture *texture, unsigned int sub_resource_idx,
2905 const struct wined3d_context *context, const struct wined3d_bo_address *data)
2907 const struct wined3d_format *format = texture->resource.format;
2908 const struct wined3d_gl_info *gl_info = context->gl_info;
2910 if (format->conv_byte_count)
2912 FIXME("Attempting to download a converted volume, format %s.\n",
2913 debug_d3dformat(format->id));
2914 return;
2917 if (data->buffer_object)
2919 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, data->buffer_object));
2920 checkGLcall("glBindBuffer");
2923 gl_info->gl_ops.gl.p_glGetTexImage(GL_TEXTURE_3D, sub_resource_idx,
2924 format->glFormat, format->glType, data->addr);
2925 checkGLcall("glGetTexImage");
2927 if (data->buffer_object)
2929 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
2930 checkGLcall("glBindBuffer");
2935 /* Context activation is done by the caller. */
2936 static void texture3d_srgb_transfer(struct wined3d_texture *texture, unsigned int sub_resource_idx,
2937 struct wined3d_context *context, BOOL dest_is_srgb)
2939 struct wined3d_texture_sub_resource *sub_resource = &texture->sub_resources[sub_resource_idx];
2940 unsigned int row_pitch, slice_pitch;
2941 struct wined3d_bo_address data;
2942 struct wined3d_box src_box;
2944 /* Optimisations are possible, but the effort should be put into either
2945 * implementing EXT_SRGB_DECODE in the driver or finding out why we
2946 * picked the wrong copy for the original upload and fixing that.
2948 * Also keep in mind that we want to avoid using resource.heap_memory
2949 * for DEFAULT pool surfaces. */
2950 WARN_(d3d_perf)("Performing slow rgb/srgb volume transfer.\n");
2951 data.buffer_object = 0;
2952 if (!(data.addr = heap_alloc(sub_resource->size)))
2953 return;
2955 wined3d_texture_get_pitch(texture, sub_resource_idx, &row_pitch, &slice_pitch);
2956 wined3d_texture_get_level_box(texture, sub_resource_idx % texture->level_count, &src_box);
2957 wined3d_texture_bind_and_dirtify(texture, context, !dest_is_srgb);
2958 texture3d_download_data(texture, sub_resource_idx, context, &data);
2959 wined3d_texture_bind_and_dirtify(texture, context, dest_is_srgb);
2960 wined3d_texture_upload_data(texture, sub_resource_idx, context, texture->resource.format,
2961 &src_box, wined3d_const_bo_address(&data), row_pitch, slice_pitch, 0, 0, 0, FALSE);
2963 heap_free(data.addr);
2966 /* Context activation is done by the caller. */
2967 static BOOL texture3d_load_location(struct wined3d_texture *texture, unsigned int sub_resource_idx,
2968 struct wined3d_context *context, DWORD location)
2970 struct wined3d_texture_sub_resource *sub_resource = &texture->sub_resources[sub_resource_idx];
2971 unsigned int row_pitch, slice_pitch;
2973 if (!wined3d_texture_prepare_location(texture, sub_resource_idx, context, location))
2974 return FALSE;
2976 switch (location)
2978 case WINED3D_LOCATION_TEXTURE_RGB:
2979 case WINED3D_LOCATION_TEXTURE_SRGB:
2980 if (sub_resource->locations & WINED3D_LOCATION_SYSMEM)
2982 struct wined3d_const_bo_address data = {0, texture->resource.heap_memory};
2983 struct wined3d_box src_box;
2985 data.addr += sub_resource->offset;
2986 wined3d_texture_bind_and_dirtify(texture, context,
2987 location == WINED3D_LOCATION_TEXTURE_SRGB);
2988 wined3d_texture_get_pitch(texture, sub_resource_idx, &row_pitch, &slice_pitch);
2989 wined3d_texture_get_level_box(texture, sub_resource_idx % texture->level_count, &src_box);
2990 wined3d_texture_upload_data(texture, sub_resource_idx, context, texture->resource.format,
2991 &src_box, &data, row_pitch, slice_pitch, 0, 0, 0, FALSE);
2993 else if (sub_resource->locations & WINED3D_LOCATION_BUFFER)
2995 struct wined3d_const_bo_address data = {sub_resource->buffer_object, NULL};
2996 struct wined3d_box src_box;
2998 wined3d_texture_bind_and_dirtify(texture, context,
2999 location == WINED3D_LOCATION_TEXTURE_SRGB);
3000 wined3d_texture_get_pitch(texture, sub_resource_idx, &row_pitch, &slice_pitch);
3001 wined3d_texture_get_level_box(texture, sub_resource_idx % texture->level_count, &src_box);
3002 wined3d_texture_upload_data(texture, sub_resource_idx, context, texture->resource.format,
3003 &src_box, &data, row_pitch, slice_pitch, 0, 0, 0, FALSE);
3005 else if (sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB)
3007 texture3d_srgb_transfer(texture, sub_resource_idx, context, TRUE);
3009 else if (sub_resource->locations & WINED3D_LOCATION_TEXTURE_SRGB)
3011 texture3d_srgb_transfer(texture, sub_resource_idx, context, FALSE);
3013 else
3015 FIXME("Implement texture loading from %s.\n", wined3d_debug_location(sub_resource->locations));
3016 return FALSE;
3018 break;
3020 case WINED3D_LOCATION_SYSMEM:
3021 if (sub_resource->locations & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB))
3023 struct wined3d_bo_address data = {0, texture->resource.heap_memory};
3025 data.addr += sub_resource->offset;
3026 if (sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB)
3027 wined3d_texture_bind_and_dirtify(texture, context, FALSE);
3028 else
3029 wined3d_texture_bind_and_dirtify(texture, context, TRUE);
3031 texture3d_download_data(texture, sub_resource_idx, context, &data);
3032 ++texture->download_count;
3034 else
3036 FIXME("Implement WINED3D_LOCATION_SYSMEM loading from %s.\n",
3037 wined3d_debug_location(sub_resource->locations));
3038 return FALSE;
3040 break;
3042 case WINED3D_LOCATION_BUFFER:
3043 if (sub_resource->locations & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB))
3045 struct wined3d_bo_address data = {sub_resource->buffer_object, NULL};
3047 if (sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB)
3048 wined3d_texture_bind_and_dirtify(texture, context, FALSE);
3049 else
3050 wined3d_texture_bind_and_dirtify(texture, context, TRUE);
3052 texture3d_download_data(texture, sub_resource_idx, context, &data);
3054 else
3056 FIXME("Implement WINED3D_LOCATION_BUFFER loading from %s.\n",
3057 wined3d_debug_location(sub_resource->locations));
3058 return FALSE;
3060 break;
3062 default:
3063 FIXME("Implement %s loading from %s.\n", wined3d_debug_location(location),
3064 wined3d_debug_location(sub_resource->locations));
3065 return FALSE;
3068 return TRUE;
3071 static const struct wined3d_texture_ops texture3d_ops =
3073 texture3d_load_location,
3076 HRESULT CDECL wined3d_texture_blt(struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx,
3077 const RECT *dst_rect, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
3078 const RECT *src_rect, DWORD flags, const struct wined3d_blt_fx *fx, enum wined3d_texture_filter_type filter)
3080 struct wined3d_box src_box = {src_rect->left, src_rect->top, src_rect->right, src_rect->bottom, 0, 1};
3081 struct wined3d_box dst_box = {dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, 0, 1};
3082 unsigned int dst_format_flags, src_format_flags = 0;
3083 HRESULT hr;
3085 TRACE("dst_texture %p, dst_sub_resource_idx %u, dst_rect %s, src_texture %p, "
3086 "src_sub_resource_idx %u, src_rect %s, flags %#x, fx %p, filter %s.\n",
3087 dst_texture, dst_sub_resource_idx, wine_dbgstr_rect(dst_rect), src_texture,
3088 src_sub_resource_idx, wine_dbgstr_rect(src_rect), flags, fx, debug_d3dtexturefiltertype(filter));
3090 if (dst_sub_resource_idx >= dst_texture->level_count * dst_texture->layer_count
3091 || dst_texture->resource.type != WINED3D_RTYPE_TEXTURE_2D)
3092 return WINED3DERR_INVALIDCALL;
3094 if (src_sub_resource_idx >= src_texture->level_count * src_texture->layer_count
3095 || src_texture->resource.type != WINED3D_RTYPE_TEXTURE_2D)
3096 return WINED3DERR_INVALIDCALL;
3098 dst_format_flags = dst_texture->resource.format_flags;
3099 if (FAILED(hr = wined3d_texture_check_box_dimensions(dst_texture,
3100 dst_sub_resource_idx % dst_texture->level_count, &dst_box)))
3101 return hr;
3103 src_format_flags = src_texture->resource.format_flags;
3104 if (FAILED(hr = wined3d_texture_check_box_dimensions(src_texture,
3105 src_sub_resource_idx % src_texture->level_count, &src_box)))
3106 return hr;
3108 if (dst_texture->sub_resources[dst_sub_resource_idx].map_count
3109 || src_texture->sub_resources[src_sub_resource_idx].map_count)
3111 WARN("Sub-resource is busy, returning WINEDDERR_SURFACEBUSY.\n");
3112 return WINEDDERR_SURFACEBUSY;
3115 if ((src_format_flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL))
3116 != (dst_format_flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)))
3118 WARN("Rejecting depth/stencil blit between incompatible formats.\n");
3119 return WINED3DERR_INVALIDCALL;
3122 if (dst_texture->resource.device != src_texture->resource.device)
3124 FIXME("Rejecting cross-device blit.\n");
3125 return E_NOTIMPL;
3128 wined3d_cs_emit_blt_sub_resource(dst_texture->resource.device->cs, &dst_texture->resource, dst_sub_resource_idx,
3129 &dst_box, &src_texture->resource, src_sub_resource_idx, &src_box, flags, fx, filter);
3131 return WINED3D_OK;
3134 HRESULT CDECL wined3d_texture_get_overlay_position(const struct wined3d_texture *texture,
3135 unsigned int sub_resource_idx, LONG *x, LONG *y)
3137 struct wined3d_overlay_info *overlay;
3139 TRACE("texture %p, sub_resource_idx %u, x %p, y %p.\n", texture, sub_resource_idx, x, y);
3141 if (!(texture->resource.usage & WINED3DUSAGE_OVERLAY)
3142 || sub_resource_idx >= texture->level_count * texture->layer_count)
3144 WARN("Invalid sub-resource specified.\n");
3145 return WINEDDERR_NOTAOVERLAYSURFACE;
3148 overlay = &texture->overlay_info[sub_resource_idx];
3149 if (!overlay->dst_texture)
3151 TRACE("Overlay not visible.\n");
3152 *x = 0;
3153 *y = 0;
3154 return WINEDDERR_OVERLAYNOTVISIBLE;
3157 *x = overlay->dst_rect.left;
3158 *y = overlay->dst_rect.top;
3160 TRACE("Returning position %d, %d.\n", *x, *y);
3162 return WINED3D_OK;
3165 HRESULT CDECL wined3d_texture_set_overlay_position(struct wined3d_texture *texture,
3166 unsigned int sub_resource_idx, LONG x, LONG y)
3168 struct wined3d_overlay_info *overlay;
3169 LONG w, h;
3171 TRACE("texture %p, sub_resource_idx %u, x %d, y %d.\n", texture, sub_resource_idx, x, y);
3173 if (!(texture->resource.usage & WINED3DUSAGE_OVERLAY)
3174 || sub_resource_idx >= texture->level_count * texture->layer_count)
3176 WARN("Invalid sub-resource specified.\n");
3177 return WINEDDERR_NOTAOVERLAYSURFACE;
3180 overlay = &texture->overlay_info[sub_resource_idx];
3181 w = overlay->dst_rect.right - overlay->dst_rect.left;
3182 h = overlay->dst_rect.bottom - overlay->dst_rect.top;
3183 SetRect(&overlay->dst_rect, x, y, x + w, y + h);
3185 return WINED3D_OK;
3188 HRESULT CDECL wined3d_texture_update_overlay(struct wined3d_texture *texture, unsigned int sub_resource_idx,
3189 const RECT *src_rect, struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx,
3190 const RECT *dst_rect, DWORD flags)
3192 struct wined3d_overlay_info *overlay;
3193 unsigned int level, dst_level;
3195 TRACE("texture %p, sub_resource_idx %u, src_rect %s, dst_texture %p, "
3196 "dst_sub_resource_idx %u, dst_rect %s, flags %#x.\n",
3197 texture, sub_resource_idx, wine_dbgstr_rect(src_rect), dst_texture,
3198 dst_sub_resource_idx, wine_dbgstr_rect(dst_rect), flags);
3200 if (!(texture->resource.usage & WINED3DUSAGE_OVERLAY) || texture->resource.type != WINED3D_RTYPE_TEXTURE_2D
3201 || sub_resource_idx >= texture->level_count * texture->layer_count)
3203 WARN("Invalid sub-resource specified.\n");
3204 return WINEDDERR_NOTAOVERLAYSURFACE;
3207 if (!dst_texture || dst_texture->resource.type != WINED3D_RTYPE_TEXTURE_2D
3208 || dst_sub_resource_idx >= dst_texture->level_count * dst_texture->layer_count)
3210 WARN("Invalid destination sub-resource specified.\n");
3211 return WINED3DERR_INVALIDCALL;
3214 overlay = &texture->overlay_info[sub_resource_idx];
3216 level = sub_resource_idx % texture->level_count;
3217 if (src_rect)
3218 overlay->src_rect = *src_rect;
3219 else
3220 SetRect(&overlay->src_rect, 0, 0,
3221 wined3d_texture_get_level_width(texture, level),
3222 wined3d_texture_get_level_height(texture, level));
3224 dst_level = dst_sub_resource_idx % dst_texture->level_count;
3225 if (dst_rect)
3226 overlay->dst_rect = *dst_rect;
3227 else
3228 SetRect(&overlay->dst_rect, 0, 0,
3229 wined3d_texture_get_level_width(dst_texture, dst_level),
3230 wined3d_texture_get_level_height(dst_texture, dst_level));
3232 if (overlay->dst_texture && (overlay->dst_texture != dst_texture
3233 || overlay->dst_sub_resource_idx != dst_sub_resource_idx || flags & WINEDDOVER_HIDE))
3235 overlay->dst_texture = NULL;
3236 list_remove(&overlay->entry);
3239 if (flags & WINEDDOVER_SHOW)
3241 if (overlay->dst_texture != dst_texture || overlay->dst_sub_resource_idx != dst_sub_resource_idx)
3243 overlay->dst_texture = dst_texture;
3244 overlay->dst_sub_resource_idx = dst_sub_resource_idx;
3245 list_add_tail(&texture->overlay_info[dst_sub_resource_idx].overlays, &overlay->entry);
3248 else if (flags & WINEDDOVER_HIDE)
3250 /* Tests show that the rectangles are erased on hide. */
3251 SetRectEmpty(&overlay->src_rect);
3252 SetRectEmpty(&overlay->dst_rect);
3253 overlay->dst_texture = NULL;
3256 return WINED3D_OK;
3259 void * CDECL wined3d_texture_get_sub_resource_parent(struct wined3d_texture *texture, unsigned int sub_resource_idx)
3261 unsigned int sub_count = texture->level_count * texture->layer_count;
3263 TRACE("texture %p, sub_resource_idx %u.\n", texture, sub_resource_idx);
3265 if (sub_resource_idx >= sub_count)
3267 WARN("sub_resource_idx %u >= sub_count %u.\n", sub_resource_idx, sub_count);
3268 return NULL;
3271 return texture->sub_resources[sub_resource_idx].parent;
3274 void CDECL wined3d_texture_set_sub_resource_parent(struct wined3d_texture *texture,
3275 unsigned int sub_resource_idx, void *parent)
3277 unsigned int sub_count = texture->level_count * texture->layer_count;
3279 TRACE("texture %p, sub_resource_idx %u, parent %p.\n", texture, sub_resource_idx, parent);
3281 if (sub_resource_idx >= sub_count)
3283 WARN("sub_resource_idx %u >= sub_count %u.\n", sub_resource_idx, sub_count);
3284 return;
3287 texture->sub_resources[sub_resource_idx].parent = parent;
3290 HRESULT CDECL wined3d_texture_get_sub_resource_desc(const struct wined3d_texture *texture,
3291 unsigned int sub_resource_idx, struct wined3d_sub_resource_desc *desc)
3293 unsigned int sub_count = texture->level_count * texture->layer_count;
3294 const struct wined3d_resource *resource;
3295 unsigned int level_idx;
3297 TRACE("texture %p, sub_resource_idx %u, desc %p.\n", texture, sub_resource_idx, desc);
3299 if (sub_resource_idx >= sub_count)
3301 WARN("sub_resource_idx %u >= sub_count %u.\n", sub_resource_idx, sub_count);
3302 return WINED3DERR_INVALIDCALL;
3305 resource = &texture->resource;
3306 desc->format = resource->format->id;
3307 desc->multisample_type = resource->multisample_type;
3308 desc->multisample_quality = resource->multisample_quality;
3309 desc->usage = resource->usage;
3310 desc->access = resource->access;
3312 level_idx = sub_resource_idx % texture->level_count;
3313 desc->width = wined3d_texture_get_level_width(texture, level_idx);
3314 desc->height = wined3d_texture_get_level_height(texture, level_idx);
3315 desc->depth = wined3d_texture_get_level_depth(texture, level_idx);
3316 desc->size = texture->sub_resources[sub_resource_idx].size;
3318 return WINED3D_OK;
3321 HRESULT CDECL wined3d_texture_create(struct wined3d_device *device, const struct wined3d_resource_desc *desc,
3322 UINT layer_count, UINT level_count, DWORD flags, const struct wined3d_sub_resource_data *data,
3323 void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_texture **texture)
3325 const struct wined3d_texture_ops *texture_ops;
3326 struct wined3d_texture *object;
3327 HRESULT hr;
3329 TRACE("device %p, desc %p, layer_count %u, level_count %u, flags %#x, data %p, "
3330 "parent %p, parent_ops %p, texture %p.\n",
3331 device, desc, layer_count, level_count, flags, data, parent, parent_ops, texture);
3333 if (!layer_count)
3335 WARN("Invalid layer count.\n");
3336 return E_INVALIDARG;
3338 if ((desc->usage & WINED3DUSAGE_LEGACY_CUBEMAP) && layer_count != 6)
3340 ERR("Invalid layer count %u for legacy cubemap.\n", layer_count);
3341 layer_count = 6;
3344 if (!level_count)
3346 WARN("Invalid level count.\n");
3347 return WINED3DERR_INVALIDCALL;
3350 if (desc->multisample_type != WINED3D_MULTISAMPLE_NONE)
3352 const struct wined3d_format *format = wined3d_get_format(&device->adapter->gl_info,
3353 desc->format, desc->usage);
3355 if (desc->multisample_type == WINED3D_MULTISAMPLE_NON_MASKABLE
3356 && desc->multisample_quality >= wined3d_popcount(format->multisample_types))
3358 WARN("Unsupported quality level %u requested for WINED3D_MULTISAMPLE_NON_MASKABLE.\n",
3359 desc->multisample_quality);
3360 return WINED3DERR_NOTAVAILABLE;
3362 if (desc->multisample_type != WINED3D_MULTISAMPLE_NON_MASKABLE
3363 && (!(format->multisample_types & 1u << (desc->multisample_type - 1))
3364 || desc->multisample_quality))
3366 WARN("Unsupported multisample type %u quality %u requested.\n", desc->multisample_type,
3367 desc->multisample_quality);
3368 return WINED3DERR_NOTAVAILABLE;
3372 switch (desc->resource_type)
3374 case WINED3D_RTYPE_TEXTURE_1D:
3375 texture_ops = &texture1d_ops;
3376 break;
3377 case WINED3D_RTYPE_TEXTURE_2D:
3378 texture_ops = &texture2d_ops;
3379 break;
3380 case WINED3D_RTYPE_TEXTURE_3D:
3381 texture_ops = &texture3d_ops;
3382 break;
3383 default:
3384 ERR("Invalid resource type %s.\n", debug_d3dresourcetype(desc->resource_type));
3385 return WINED3DERR_INVALIDCALL;
3388 if (!(object = heap_alloc_zero(FIELD_OFFSET(struct wined3d_texture,
3389 sub_resources[level_count * layer_count]))))
3390 return E_OUTOFMEMORY;
3392 if (FAILED(hr = wined3d_texture_init(object, desc, layer_count,
3393 level_count, flags, device, parent, parent_ops, texture_ops)))
3395 WARN("Failed to initialize texture, returning %#x.\n", hr);
3396 heap_free(object);
3397 return hr;
3400 /* FIXME: We'd like to avoid ever allocating system memory for the texture
3401 * in this case. */
3402 if (data)
3404 unsigned int sub_count = level_count * layer_count;
3405 unsigned int i;
3407 for (i = 0; i < sub_count; ++i)
3409 if (!data[i].data)
3411 WARN("Invalid sub-resource data specified for sub-resource %u.\n", i);
3412 wined3d_texture_cleanup_sync(object);
3413 heap_free(object);
3414 return E_INVALIDARG;
3418 for (i = 0; i < sub_count; ++i)
3420 wined3d_device_update_sub_resource(device, &object->resource,
3421 i, NULL, data[i].data, data[i].row_pitch, data[i].slice_pitch, 0);
3425 TRACE("Created texture %p.\n", object);
3426 *texture = object;
3428 return WINED3D_OK;
3431 HRESULT CDECL wined3d_texture_get_dc(struct wined3d_texture *texture, unsigned int sub_resource_idx, HDC *dc)
3433 struct wined3d_device *device = texture->resource.device;
3434 struct wined3d_texture_sub_resource *sub_resource;
3435 struct wined3d_dc_info *dc_info;
3437 TRACE("texture %p, sub_resource_idx %u, dc %p.\n", texture, sub_resource_idx, dc);
3439 if (!(texture->flags & WINED3D_TEXTURE_GET_DC))
3441 WARN("Texture does not support GetDC\n");
3442 /* Don't touch the DC */
3443 return WINED3DERR_INVALIDCALL;
3446 if (!(sub_resource = wined3d_texture_get_sub_resource(texture, sub_resource_idx)))
3447 return WINED3DERR_INVALIDCALL;
3449 if (texture->resource.type != WINED3D_RTYPE_TEXTURE_2D)
3451 WARN("Not supported on %s resources.\n", debug_d3dresourcetype(texture->resource.type));
3452 return WINED3DERR_INVALIDCALL;
3455 if (texture->resource.map_count && !(texture->flags & WINED3D_TEXTURE_GET_DC_LENIENT))
3456 return WINED3DERR_INVALIDCALL;
3458 if (!(dc_info = texture->dc_info) || !dc_info[sub_resource_idx].dc)
3460 struct wined3d_texture_idx texture_idx = {texture, sub_resource_idx};
3462 wined3d_cs_init_object(device->cs, wined3d_texture_create_dc, &texture_idx);
3463 device->cs->ops->finish(device->cs, WINED3D_CS_QUEUE_DEFAULT);
3464 if (!(dc_info = texture->dc_info) || !dc_info[sub_resource_idx].dc)
3465 return WINED3DERR_INVALIDCALL;
3468 if (!(texture->flags & WINED3D_TEXTURE_GET_DC_LENIENT))
3469 texture->flags |= WINED3D_TEXTURE_DC_IN_USE;
3470 ++texture->resource.map_count;
3471 ++sub_resource->map_count;
3473 *dc = dc_info[sub_resource_idx].dc;
3474 TRACE("Returning dc %p.\n", *dc);
3476 return WINED3D_OK;
3479 HRESULT CDECL wined3d_texture_release_dc(struct wined3d_texture *texture, unsigned int sub_resource_idx, HDC dc)
3481 struct wined3d_device *device = texture->resource.device;
3482 struct wined3d_texture_sub_resource *sub_resource;
3483 struct wined3d_dc_info *dc_info;
3485 TRACE("texture %p, sub_resource_idx %u, dc %p.\n", texture, sub_resource_idx, dc);
3487 if (!(sub_resource = wined3d_texture_get_sub_resource(texture, sub_resource_idx)))
3488 return WINED3DERR_INVALIDCALL;
3490 if (texture->resource.type != WINED3D_RTYPE_TEXTURE_2D)
3492 WARN("Not supported on %s resources.\n", debug_d3dresourcetype(texture->resource.type));
3493 return WINED3DERR_INVALIDCALL;
3496 if (!(texture->flags & (WINED3D_TEXTURE_GET_DC_LENIENT | WINED3D_TEXTURE_DC_IN_USE)))
3497 return WINED3DERR_INVALIDCALL;
3499 if (!(dc_info = texture->dc_info) || dc_info[sub_resource_idx].dc != dc)
3501 WARN("Application tries to release invalid DC %p, sub-resource DC is %p.\n",
3502 dc, dc_info ? dc_info[sub_resource_idx].dc : NULL);
3503 return WINED3DERR_INVALIDCALL;
3506 if (!(texture->resource.usage & WINED3DUSAGE_OWNDC) && !(device->wined3d->flags & WINED3D_NO3D))
3508 struct wined3d_texture_idx texture_idx = {texture, sub_resource_idx};
3510 wined3d_cs_destroy_object(device->cs, wined3d_texture_destroy_dc, &texture_idx);
3511 device->cs->ops->finish(device->cs, WINED3D_CS_QUEUE_DEFAULT);
3514 --sub_resource->map_count;
3515 if (!--texture->resource.map_count && texture->update_map_binding)
3516 wined3d_texture_update_map_binding(texture);
3517 if (!(texture->flags & WINED3D_TEXTURE_GET_DC_LENIENT))
3518 texture->flags &= ~WINED3D_TEXTURE_DC_IN_USE;
3520 return WINED3D_OK;
3523 void wined3d_texture_upload_from_texture(struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx,
3524 unsigned int dst_x, unsigned int dst_y, unsigned int dst_z, struct wined3d_texture *src_texture,
3525 unsigned int src_sub_resource_idx, const struct wined3d_box *src_box)
3527 unsigned int src_row_pitch, src_slice_pitch;
3528 unsigned int update_w, update_h, update_d;
3529 unsigned int src_level, dst_level;
3530 struct wined3d_context *context;
3531 struct wined3d_bo_address data;
3533 TRACE("dst_texture %p, dst_sub_resource_idx %u, dst_x %u, dst_y %u, dst_z %u, "
3534 "src_texture %p, src_sub_resource_idx %u, src_box %s.\n",
3535 dst_texture, dst_sub_resource_idx, dst_x, dst_y, dst_z,
3536 src_texture, src_sub_resource_idx, debug_box(src_box));
3538 context = context_acquire(dst_texture->resource.device, NULL, 0);
3540 /* Only load the sub-resource for partial updates. For newly allocated
3541 * textures the texture wouldn't be the current location, and we'd upload
3542 * zeroes just to overwrite them again. */
3543 update_w = src_box->right - src_box->left;
3544 update_h = src_box->bottom - src_box->top;
3545 update_d = src_box->back - src_box->front;
3546 dst_level = dst_sub_resource_idx % dst_texture->level_count;
3547 if (update_w == wined3d_texture_get_level_width(dst_texture, dst_level)
3548 && update_h == wined3d_texture_get_level_height(dst_texture, dst_level)
3549 && update_d == wined3d_texture_get_level_depth(dst_texture, dst_level))
3550 wined3d_texture_prepare_texture(dst_texture, context, FALSE);
3551 else
3552 wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB);
3553 wined3d_texture_bind_and_dirtify(dst_texture, context, FALSE);
3555 src_level = src_sub_resource_idx % src_texture->level_count;
3556 wined3d_texture_get_memory(src_texture, src_sub_resource_idx, &data,
3557 src_texture->sub_resources[src_sub_resource_idx].locations);
3558 wined3d_texture_get_pitch(src_texture, src_level, &src_row_pitch, &src_slice_pitch);
3560 wined3d_texture_upload_data(dst_texture, dst_sub_resource_idx, context, src_texture->resource.format,
3561 src_box, wined3d_const_bo_address(&data), src_row_pitch, src_slice_pitch, dst_x, dst_y, dst_z, FALSE);
3563 context_release(context);
3565 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB);
3566 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB);