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