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 BOOL
wined3d_texture_use_pbo(const struct wined3d_texture
*texture
, const struct wined3d_gl_info
*gl_info
)
35 return texture
->resource
.pool
== WINED3D_POOL_DEFAULT
36 && texture
->resource
.access_flags
& WINED3D_RESOURCE_ACCESS_CPU
37 && gl_info
->supported
[ARB_PIXEL_BUFFER_OBJECT
]
38 && !texture
->resource
.format
->convert
39 && !(texture
->flags
& (WINED3D_TEXTURE_PIN_SYSMEM
| WINED3D_TEXTURE_COND_NP2_EMULATED
));
42 static BOOL
wined3d_texture_use_immutable_storage(const struct wined3d_texture
*texture
,
43 const struct wined3d_gl_info
*gl_info
)
45 /* We don't expect to create texture views for textures with height-scaled formats.
46 * Besides, ARB_texture_storage doesn't allow specifying exact sizes for all levels. */
47 return gl_info
->supported
[ARB_TEXTURE_STORAGE
]
48 && !(texture
->resource
.format_flags
& WINED3DFMT_FLAG_HEIGHT_SCALE
);
51 GLenum
wined3d_texture_get_gl_buffer(const struct wined3d_texture
*texture
)
53 const struct wined3d_swapchain
*swapchain
= texture
->swapchain
;
55 TRACE("texture %p.\n", texture
);
59 ERR("Texture %p is not part of a swapchain.\n", texture
);
63 if (swapchain
->back_buffers
&& swapchain
->back_buffers
[0] == texture
)
65 if (swapchain
->render_to_fbo
)
67 TRACE("Returning GL_COLOR_ATTACHMENT0.\n");
68 return GL_COLOR_ATTACHMENT0
;
70 TRACE("Returning GL_BACK.\n");
73 else if (texture
== swapchain
->front_buffer
)
75 TRACE("Returning GL_FRONT.\n");
79 FIXME("Higher back buffer, returning GL_BACK.\n");
83 static DWORD
wined3d_resource_access_from_location(DWORD location
)
87 case WINED3D_LOCATION_DISCARDED
:
90 case WINED3D_LOCATION_SYSMEM
:
91 case WINED3D_LOCATION_USER_MEMORY
:
92 return WINED3D_RESOURCE_ACCESS_CPU
;
94 case WINED3D_LOCATION_BUFFER
:
95 case WINED3D_LOCATION_DRAWABLE
:
96 case WINED3D_LOCATION_TEXTURE_RGB
:
97 case WINED3D_LOCATION_TEXTURE_SRGB
:
98 case WINED3D_LOCATION_RB_MULTISAMPLE
:
99 case WINED3D_LOCATION_RB_RESOLVED
:
100 return WINED3D_RESOURCE_ACCESS_GPU
;
103 FIXME("Unhandled location %#x.\n", location
);
108 static void wined3d_texture_evict_sysmem(struct wined3d_texture
*texture
)
110 struct wined3d_texture_sub_resource
*sub_resource
;
111 unsigned int i
, sub_count
;
113 if (texture
->flags
& (WINED3D_TEXTURE_CONVERTED
| WINED3D_TEXTURE_PIN_SYSMEM
)
114 || texture
->download_count
> WINED3D_TEXTURE_DYNAMIC_MAP_THRESHOLD
)
116 TRACE("Not evicting system memory for texture %p.\n", texture
);
120 TRACE("Evicting system memory for texture %p.\n", texture
);
122 sub_count
= texture
->level_count
* texture
->layer_count
;
123 for (i
= 0; i
< sub_count
; ++i
)
125 sub_resource
= &texture
->sub_resources
[i
];
126 if (sub_resource
->locations
== WINED3D_LOCATION_SYSMEM
)
127 ERR("WINED3D_LOCATION_SYSMEM is the only location for sub-resource %u of texture %p.\n",
129 sub_resource
->locations
&= ~WINED3D_LOCATION_SYSMEM
;
131 wined3d_resource_free_sysmem(&texture
->resource
);
134 void wined3d_texture_validate_location(struct wined3d_texture
*texture
,
135 unsigned int sub_resource_idx
, DWORD location
)
137 struct wined3d_texture_sub_resource
*sub_resource
;
138 DWORD previous_locations
;
140 TRACE("texture %p, sub_resource_idx %u, location %s.\n",
141 texture
, sub_resource_idx
, wined3d_debug_location(location
));
143 sub_resource
= &texture
->sub_resources
[sub_resource_idx
];
144 previous_locations
= sub_resource
->locations
;
145 sub_resource
->locations
|= location
;
146 if (previous_locations
== WINED3D_LOCATION_SYSMEM
&& location
!= WINED3D_LOCATION_SYSMEM
147 && !--texture
->sysmem_count
)
148 wined3d_texture_evict_sysmem(texture
);
150 TRACE("New locations flags are %s.\n", wined3d_debug_location(sub_resource
->locations
));
153 static void wined3d_texture_set_dirty(struct wined3d_texture
*texture
)
155 texture
->flags
&= ~(WINED3D_TEXTURE_RGB_VALID
| WINED3D_TEXTURE_SRGB_VALID
);
158 void wined3d_texture_invalidate_location(struct wined3d_texture
*texture
,
159 unsigned int sub_resource_idx
, DWORD location
)
161 struct wined3d_texture_sub_resource
*sub_resource
;
163 TRACE("texture %p, sub_resource_idx %u, location %s.\n",
164 texture
, sub_resource_idx
, wined3d_debug_location(location
));
166 if (location
& (WINED3D_LOCATION_TEXTURE_RGB
| WINED3D_LOCATION_TEXTURE_SRGB
))
167 wined3d_texture_set_dirty(texture
);
169 sub_resource
= &texture
->sub_resources
[sub_resource_idx
];
170 sub_resource
->locations
&= ~location
;
171 if (sub_resource
->locations
== WINED3D_LOCATION_SYSMEM
)
172 ++texture
->sysmem_count
;
174 TRACE("New locations flags are %s.\n", wined3d_debug_location(sub_resource
->locations
));
176 if (!sub_resource
->locations
)
177 ERR("Sub-resource %u of texture %p does not have any up to date location.\n",
178 sub_resource_idx
, texture
);
181 /* Context activation is done by the caller. Context may be NULL in
182 * WINED3D_NO3D mode. */
183 BOOL
wined3d_texture_load_location(struct wined3d_texture
*texture
,
184 unsigned int sub_resource_idx
, struct wined3d_context
*context
, DWORD location
)
186 DWORD current
= texture
->sub_resources
[sub_resource_idx
].locations
;
189 TRACE("texture %p, sub_resource_idx %u, context %p, location %s.\n",
190 texture
, sub_resource_idx
, context
, wined3d_debug_location(location
));
192 TRACE("Current resource location %s.\n", wined3d_debug_location(current
));
194 if (current
& location
)
196 TRACE("Location %s is already up to date.\n", wined3d_debug_location(location
));
202 DWORD required_access
= wined3d_resource_access_from_location(location
);
203 if ((texture
->resource
.access_flags
& required_access
) != required_access
)
204 WARN("Operation requires %#x access, but texture only has %#x.\n",
205 required_access
, texture
->resource
.access_flags
);
208 if (current
& WINED3D_LOCATION_DISCARDED
)
210 TRACE("Sub-resource previously discarded, nothing to do.\n");
211 if (!wined3d_texture_prepare_location(texture
, sub_resource_idx
, context
, location
))
213 wined3d_texture_validate_location(texture
, sub_resource_idx
, location
);
214 wined3d_texture_invalidate_location(texture
, sub_resource_idx
, WINED3D_LOCATION_DISCARDED
);
220 ERR("Sub-resource %u of texture %p does not have any up to date location.\n",
221 sub_resource_idx
, texture
);
222 wined3d_texture_validate_location(texture
, sub_resource_idx
, WINED3D_LOCATION_DISCARDED
);
223 return wined3d_texture_load_location(texture
, sub_resource_idx
, context
, location
);
226 if ((ret
= texture
->texture_ops
->texture_load_location(texture
, sub_resource_idx
, context
, location
)))
227 wined3d_texture_validate_location(texture
, sub_resource_idx
, location
);
232 /* Context activation is done by the caller. */
233 void *wined3d_texture_map_bo_address(const struct wined3d_bo_address
*data
, size_t size
,
234 const struct wined3d_gl_info
*gl_info
, GLenum binding
, DWORD flags
)
238 if (!data
->buffer_object
)
241 GL_EXTCALL(glBindBuffer(binding
, data
->buffer_object
));
243 if (gl_info
->supported
[ARB_MAP_BUFFER_RANGE
])
245 GLbitfield map_flags
= wined3d_resource_gl_map_flags(flags
) & ~GL_MAP_FLUSH_EXPLICIT_BIT
;
246 memory
= GL_EXTCALL(glMapBufferRange(binding
, (INT_PTR
)data
->addr
, size
, map_flags
));
250 memory
= GL_EXTCALL(glMapBuffer(binding
, wined3d_resource_gl_legacy_map_flags(flags
)));
251 memory
+= (INT_PTR
)data
->addr
;
254 GL_EXTCALL(glBindBuffer(binding
, 0));
255 checkGLcall("Map buffer object");
260 /* Context activation is done by the caller. */
261 void wined3d_texture_unmap_bo_address(const struct wined3d_bo_address
*data
,
262 const struct wined3d_gl_info
*gl_info
, GLenum binding
)
264 if (!data
->buffer_object
)
267 GL_EXTCALL(glBindBuffer(binding
, data
->buffer_object
));
268 GL_EXTCALL(glUnmapBuffer(binding
));
269 GL_EXTCALL(glBindBuffer(binding
, 0));
270 checkGLcall("Unmap buffer object");
273 void wined3d_texture_get_memory(struct wined3d_texture
*texture
, unsigned int sub_resource_idx
,
274 struct wined3d_bo_address
*data
, DWORD locations
)
276 struct wined3d_texture_sub_resource
*sub_resource
;
278 TRACE("texture %p, sub_resource_idx %u, data %p, locations %s.\n",
279 texture
, sub_resource_idx
, data
, wined3d_debug_location(locations
));
281 sub_resource
= &texture
->sub_resources
[sub_resource_idx
];
282 if (locations
& WINED3D_LOCATION_BUFFER
)
285 data
->buffer_object
= sub_resource
->buffer_object
;
288 if (locations
& WINED3D_LOCATION_USER_MEMORY
)
290 data
->addr
= texture
->user_memory
;
291 data
->buffer_object
= 0;
294 if (locations
& WINED3D_LOCATION_SYSMEM
)
296 data
->addr
= texture
->resource
.heap_memory
;
297 data
->addr
+= sub_resource
->offset
;
298 data
->buffer_object
= 0;
302 ERR("Unexpected locations %s.\n", wined3d_debug_location(locations
));
304 data
->buffer_object
= 0;
307 static HRESULT
wined3d_texture_init(struct wined3d_texture
*texture
, const struct wined3d_texture_ops
*texture_ops
,
308 UINT layer_count
, UINT level_count
, const struct wined3d_resource_desc
*desc
, DWORD flags
,
309 struct wined3d_device
*device
, void *parent
, const struct wined3d_parent_ops
*parent_ops
,
310 const struct wined3d_resource_ops
*resource_ops
)
312 unsigned int i
, j
, size
, offset
= 0;
313 const struct wined3d_format
*format
;
316 TRACE("texture %p, texture_ops %p, layer_count %u, level_count %u, resource_type %s, format %s, "
317 "multisample_type %#x, multisample_quality %#x, usage %s, pool %s, width %u, height %u, depth %u, "
318 "flags %#x, device %p, parent %p, parent_ops %p, resource_ops %p.\n",
319 texture
, texture_ops
, layer_count
, level_count
, debug_d3dresourcetype(desc
->resource_type
),
320 debug_d3dformat(desc
->format
), desc
->multisample_type
, desc
->multisample_quality
,
321 debug_d3dusage(desc
->usage
), debug_d3dpool(desc
->pool
), desc
->width
, desc
->height
, desc
->depth
,
322 flags
, device
, parent
, parent_ops
, resource_ops
);
324 if (!desc
->width
|| !desc
->height
|| !desc
->depth
)
325 return WINED3DERR_INVALIDCALL
;
327 format
= wined3d_get_format(&device
->adapter
->gl_info
, desc
->format
, desc
->usage
);
329 for (i
= 0; i
< layer_count
; ++i
)
331 for (j
= 0; j
< level_count
; ++j
)
333 unsigned int idx
= i
* level_count
+ j
;
335 size
= wined3d_format_calculate_size(format
, device
->surface_alignment
,
336 max(1, desc
->width
>> j
), max(1, desc
->height
>> j
), max(1, desc
->depth
>> j
));
337 texture
->sub_resources
[idx
].offset
= offset
;
338 texture
->sub_resources
[idx
].size
= size
;
341 offset
= (offset
+ (RESOURCE_ALIGNMENT
- 1)) & ~(RESOURCE_ALIGNMENT
- 1);
345 return WINED3DERR_INVALIDCALL
;
347 if (FAILED(hr
= resource_init(&texture
->resource
, device
, desc
->resource_type
, format
,
348 desc
->multisample_type
, desc
->multisample_quality
, desc
->usage
, desc
->pool
,
349 desc
->width
, desc
->height
, desc
->depth
, offset
, parent
, parent_ops
, resource_ops
)))
351 static unsigned int once
;
353 /* DXTn 3D textures are not supported. Do not write the ERR for them. */
354 if ((desc
->format
== WINED3DFMT_DXT1
|| desc
->format
== WINED3DFMT_DXT2
|| desc
->format
== WINED3DFMT_DXT3
355 || desc
->format
== WINED3DFMT_DXT4
|| desc
->format
== WINED3DFMT_DXT5
)
356 && !(format
->flags
[WINED3D_GL_RES_TYPE_TEX_2D
] & WINED3DFMT_FLAG_TEXTURE
)
357 && desc
->resource_type
!= WINED3D_RTYPE_TEXTURE_3D
&& !once
++)
358 ERR_(winediag
)("The application tried to create a DXTn texture, but the driver does not support them.\n");
360 WARN("Failed to initialize resource, returning %#x\n", hr
);
363 wined3d_resource_update_draw_binding(&texture
->resource
);
364 if ((flags
& WINED3D_TEXTURE_CREATE_MAPPABLE
) || desc
->format
== WINED3DFMT_D16_LOCKABLE
)
365 texture
->resource
.access_flags
|= WINED3D_RESOURCE_ACCESS_CPU
;
367 texture
->texture_ops
= texture_ops
;
369 texture
->layer_count
= layer_count
;
370 texture
->level_count
= level_count
;
371 texture
->filter_type
= (desc
->usage
& WINED3DUSAGE_AUTOGENMIPMAP
) ? WINED3D_TEXF_LINEAR
: WINED3D_TEXF_NONE
;
373 texture
->flags
|= WINED3D_TEXTURE_POW2_MAT_IDENT
| WINED3D_TEXTURE_NORMALIZED_COORDS
;
374 if (flags
& WINED3D_TEXTURE_CREATE_GET_DC_LENIENT
)
375 texture
->flags
|= WINED3D_TEXTURE_PIN_SYSMEM
| WINED3D_TEXTURE_GET_DC_LENIENT
;
376 if (flags
& (WINED3D_TEXTURE_CREATE_GET_DC
| WINED3D_TEXTURE_CREATE_GET_DC_LENIENT
))
377 texture
->flags
|= WINED3D_TEXTURE_GET_DC
;
378 if (flags
& WINED3D_TEXTURE_CREATE_DISCARD
)
379 texture
->flags
|= WINED3D_TEXTURE_DISCARD
;
384 /* Context activation is done by the caller. */
385 static void wined3d_texture_remove_buffer_object(struct wined3d_texture
*texture
,
386 unsigned int sub_resource_idx
, const struct wined3d_gl_info
*gl_info
)
388 GLuint
*buffer_object
;
390 buffer_object
= &texture
->sub_resources
[sub_resource_idx
].buffer_object
;
391 GL_EXTCALL(glDeleteBuffers(1, buffer_object
));
392 checkGLcall("glDeleteBuffers");
393 wined3d_texture_invalidate_location(texture
, sub_resource_idx
, WINED3D_LOCATION_BUFFER
);
396 TRACE("Deleted buffer object %u for texture %p, sub-resource %u.\n",
397 *buffer_object
, texture
, sub_resource_idx
);
400 static void wined3d_texture_update_map_binding(struct wined3d_texture
*texture
)
402 unsigned int sub_count
= texture
->level_count
* texture
->layer_count
;
403 const struct wined3d_device
*device
= texture
->resource
.device
;
404 DWORD map_binding
= texture
->update_map_binding
;
405 struct wined3d_context
*context
= NULL
;
408 if (device
->d3d_initialized
)
409 context
= context_acquire(device
, NULL
);
411 for (i
= 0; i
< sub_count
; ++i
)
413 if (texture
->sub_resources
[i
].locations
== texture
->resource
.map_binding
414 && !wined3d_texture_load_location(texture
, i
, context
, map_binding
))
415 ERR("Failed to load location %s.\n", wined3d_debug_location(map_binding
));
416 if (texture
->resource
.map_binding
== WINED3D_LOCATION_BUFFER
)
417 wined3d_texture_remove_buffer_object(texture
, i
, context
->gl_info
);
421 context_release(context
);
423 texture
->resource
.map_binding
= map_binding
;
424 texture
->update_map_binding
= 0;
427 void wined3d_texture_set_map_binding(struct wined3d_texture
*texture
, DWORD map_binding
)
429 texture
->update_map_binding
= map_binding
;
430 if (!texture
->resource
.map_count
)
431 wined3d_texture_update_map_binding(texture
);
434 /* A GL context is provided by the caller */
435 static void gltexture_delete(struct wined3d_device
*device
, const struct wined3d_gl_info
*gl_info
,
436 struct gl_texture
*tex
)
438 context_gl_resource_released(device
, tex
->name
, FALSE
);
439 gl_info
->gl_ops
.gl
.p_glDeleteTextures(1, &tex
->name
);
443 /* Context activation is done by the caller. */
444 /* The caller is responsible for binding the correct texture. */
445 static void wined3d_texture_allocate_gl_mutable_storage(struct wined3d_texture
*texture
,
446 GLenum gl_internal_format
, const struct wined3d_format
*format
,
447 const struct wined3d_gl_info
*gl_info
)
449 unsigned int i
, sub_call_count
;
451 sub_call_count
= texture
->level_count
;
452 if (texture
->target
!= GL_TEXTURE_2D_ARRAY
)
453 sub_call_count
*= texture
->layer_count
;
455 for (i
= 0; i
< sub_call_count
; ++i
)
457 struct wined3d_surface
*surface
= texture
->sub_resources
[i
].u
.surface
;
458 GLsizei width
, height
;
460 width
= wined3d_texture_get_level_pow2_width(texture
, surface
->texture_level
);
461 height
= wined3d_texture_get_level_pow2_height(texture
, surface
->texture_level
);
462 if (texture
->resource
.format_flags
& WINED3DFMT_FLAG_HEIGHT_SCALE
)
464 height
*= format
->height_scale
.numerator
;
465 height
/= format
->height_scale
.denominator
;
468 TRACE("surface %p, target %#x, level %u, width %u, height %u.\n",
469 surface
, surface
->texture_target
, surface
->texture_level
, width
, height
);
471 if (texture
->target
== GL_TEXTURE_2D_ARRAY
)
473 GL_EXTCALL(glTexImage3D(surface
->texture_target
, surface
->texture_level
,
474 gl_internal_format
, width
, height
, texture
->layer_count
, 0,
475 format
->glFormat
, format
->glType
, NULL
));
476 checkGLcall("glTexImage3D");
480 gl_info
->gl_ops
.gl
.p_glTexImage2D(surface
->texture_target
, surface
->texture_level
,
481 gl_internal_format
, width
, height
, 0, format
->glFormat
, format
->glType
, NULL
);
482 checkGLcall("glTexImage2D");
487 /* Context activation is done by the caller. */
488 /* The caller is responsible for binding the correct texture. */
489 static void wined3d_texture_allocate_gl_immutable_storage(struct wined3d_texture
*texture
,
490 GLenum gl_internal_format
, const struct wined3d_gl_info
*gl_info
)
492 GLsizei width
= wined3d_texture_get_level_pow2_width(texture
, 0);
493 GLsizei height
= wined3d_texture_get_level_pow2_height(texture
, 0);
495 if (texture
->target
== GL_TEXTURE_2D_ARRAY
)
497 GL_EXTCALL(glTexStorage3D(texture
->target
, texture
->level_count
, gl_internal_format
,
498 width
, height
, texture
->layer_count
));
499 checkGLcall("glTexStorage3D");
503 GL_EXTCALL(glTexStorage2D(texture
->target
, texture
->level_count
, gl_internal_format
,
505 checkGLcall("glTexStorage2D");
509 static void wined3d_texture_unload_gl_texture(struct wined3d_texture
*texture
)
511 struct wined3d_device
*device
= texture
->resource
.device
;
512 const struct wined3d_gl_info
*gl_info
= NULL
;
513 struct wined3d_context
*context
= NULL
;
515 if (texture
->texture_rgb
.name
|| texture
->texture_srgb
.name
516 || texture
->rb_multisample
|| texture
->rb_resolved
)
518 context
= context_acquire(device
, NULL
);
519 gl_info
= context
->gl_info
;
522 if (texture
->texture_rgb
.name
)
523 gltexture_delete(device
, context
->gl_info
, &texture
->texture_rgb
);
525 if (texture
->texture_srgb
.name
)
526 gltexture_delete(device
, context
->gl_info
, &texture
->texture_srgb
);
528 if (texture
->rb_multisample
)
530 TRACE("Deleting multisample renderbuffer %u.\n", texture
->rb_multisample
);
531 context_gl_resource_released(device
, texture
->rb_multisample
, TRUE
);
532 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &texture
->rb_multisample
);
533 texture
->rb_multisample
= 0;
536 if (texture
->rb_resolved
)
538 TRACE("Deleting resolved renderbuffer %u.\n", texture
->rb_resolved
);
539 context_gl_resource_released(device
, texture
->rb_resolved
, TRUE
);
540 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &texture
->rb_resolved
);
541 texture
->rb_resolved
= 0;
544 if (context
) context_release(context
);
546 wined3d_texture_set_dirty(texture
);
548 resource_unload(&texture
->resource
);
551 static void wined3d_texture_sub_resources_destroyed(struct wined3d_texture
*texture
)
553 unsigned int sub_count
= texture
->level_count
* texture
->layer_count
;
554 struct wined3d_texture_sub_resource
*sub_resource
;
557 for (i
= 0; i
< sub_count
; ++i
)
559 sub_resource
= &texture
->sub_resources
[i
];
560 if (sub_resource
->parent
)
562 TRACE("sub-resource %u.\n", i
);
563 sub_resource
->parent_ops
->wined3d_object_destroyed(sub_resource
->parent
);
564 sub_resource
->parent
= NULL
;
569 static void wined3d_texture_cleanup(struct wined3d_texture
*texture
)
571 unsigned int sub_count
= texture
->level_count
* texture
->layer_count
;
572 struct wined3d_device
*device
= texture
->resource
.device
;
573 struct wined3d_context
*context
= NULL
;
574 const struct wined3d_gl_info
*gl_info
;
575 GLuint buffer_object
;
578 TRACE("texture %p.\n", texture
);
580 for (i
= 0; i
< sub_count
; ++i
)
582 if (!(buffer_object
= texture
->sub_resources
[i
].buffer_object
))
585 TRACE("Deleting buffer object %u.\n", buffer_object
);
587 /* We may not be able to get a context in wined3d_texture_cleanup() in
588 * general, but if a buffer object was previously created we can. */
591 context
= context_acquire(device
, NULL
);
592 gl_info
= context
->gl_info
;
595 GL_EXTCALL(glDeleteBuffers(1, &buffer_object
));
598 context_release(context
);
600 texture
->texture_ops
->texture_cleanup_sub_resources(texture
);
601 wined3d_texture_unload_gl_texture(texture
);
604 void wined3d_texture_set_swapchain(struct wined3d_texture
*texture
, struct wined3d_swapchain
*swapchain
)
606 texture
->swapchain
= swapchain
;
607 wined3d_resource_update_draw_binding(&texture
->resource
);
610 /* Context activation is done by the caller. */
611 void wined3d_texture_bind(struct wined3d_texture
*texture
,
612 struct wined3d_context
*context
, BOOL srgb
)
614 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
615 const struct wined3d_format
*format
= texture
->resource
.format
;
616 const struct color_fixup_desc fixup
= format
->color_fixup
;
617 struct gl_texture
*gl_tex
;
620 TRACE("texture %p, context %p, srgb %#x.\n", texture
, context
, srgb
);
622 if (!needs_separate_srgb_gl_texture(context
, texture
))
625 /* sRGB mode cache for preload() calls outside drawprim. */
627 texture
->flags
|= WINED3D_TEXTURE_IS_SRGB
;
629 texture
->flags
&= ~WINED3D_TEXTURE_IS_SRGB
;
631 gl_tex
= wined3d_texture_get_gl_texture(texture
, srgb
);
632 target
= texture
->target
;
636 context_bind_texture(context
, target
, gl_tex
->name
);
640 gl_info
->gl_ops
.gl
.p_glGenTextures(1, &gl_tex
->name
);
641 checkGLcall("glGenTextures");
642 TRACE("Generated texture %d.\n", gl_tex
->name
);
646 ERR("Failed to generate a texture name.\n");
650 /* Initialise the state of the texture object to the OpenGL defaults, not
651 * the wined3d defaults. */
652 gl_tex
->sampler_desc
.address_u
= WINED3D_TADDRESS_WRAP
;
653 gl_tex
->sampler_desc
.address_v
= WINED3D_TADDRESS_WRAP
;
654 gl_tex
->sampler_desc
.address_w
= WINED3D_TADDRESS_WRAP
;
655 memset(gl_tex
->sampler_desc
.border_color
, 0, sizeof(gl_tex
->sampler_desc
.border_color
));
656 gl_tex
->sampler_desc
.mag_filter
= WINED3D_TEXF_LINEAR
;
657 gl_tex
->sampler_desc
.min_filter
= WINED3D_TEXF_POINT
; /* GL_NEAREST_MIPMAP_LINEAR */
658 gl_tex
->sampler_desc
.mip_filter
= WINED3D_TEXF_LINEAR
; /* GL_NEAREST_MIPMAP_LINEAR */
659 gl_tex
->sampler_desc
.lod_bias
= 0.0f
;
660 gl_tex
->sampler_desc
.min_lod
= -1000.0f
;
661 gl_tex
->sampler_desc
.max_lod
= 1000.0f
;
662 gl_tex
->sampler_desc
.max_anisotropy
= 1;
663 gl_tex
->sampler_desc
.compare
= FALSE
;
664 gl_tex
->sampler_desc
.comparison_func
= WINED3D_CMP_LESSEQUAL
;
665 if (context
->gl_info
->supported
[EXT_TEXTURE_SRGB_DECODE
])
666 gl_tex
->sampler_desc
.srgb_decode
= TRUE
;
668 gl_tex
->sampler_desc
.srgb_decode
= srgb
;
669 gl_tex
->base_level
= 0;
670 wined3d_texture_set_dirty(texture
);
672 context_bind_texture(context
, target
, gl_tex
->name
);
674 if (texture
->resource
.usage
& WINED3DUSAGE_AUTOGENMIPMAP
)
676 gl_info
->gl_ops
.gl
.p_glTexParameteri(target
, GL_GENERATE_MIPMAP_SGIS
, GL_TRUE
);
677 checkGLcall("glTexParameteri(target, GL_GENERATE_MIPMAP_SGIS, GL_TRUE)");
680 /* For a new texture we have to set the texture levels after binding the
681 * texture. Beware that texture rectangles do not support mipmapping, but
682 * set the maxmiplevel if we're relying on the partial
683 * GL_ARB_texture_non_power_of_two emulation with texture rectangles.
684 * (I.e., do not care about cond_np2 here, just look for
685 * GL_TEXTURE_RECTANGLE_ARB.) */
686 if (target
!= GL_TEXTURE_RECTANGLE_ARB
)
688 TRACE("Setting GL_TEXTURE_MAX_LEVEL to %u.\n", texture
->level_count
- 1);
689 gl_info
->gl_ops
.gl
.p_glTexParameteri(target
, GL_TEXTURE_MAX_LEVEL
, texture
->level_count
- 1);
690 checkGLcall("glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, texture->level_count)");
693 if (target
== GL_TEXTURE_CUBE_MAP_ARB
)
695 /* Cubemaps are always set to clamp, regardless of the sampler state. */
696 gl_info
->gl_ops
.gl
.p_glTexParameteri(target
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
697 gl_info
->gl_ops
.gl
.p_glTexParameteri(target
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
698 gl_info
->gl_ops
.gl
.p_glTexParameteri(target
, GL_TEXTURE_WRAP_R
, GL_CLAMP_TO_EDGE
);
701 if (texture
->flags
& WINED3D_TEXTURE_COND_NP2
)
703 /* Conditinal non power of two textures use a different clamping
704 * default. If we're using the GL_WINE_normalized_texrect partial
705 * driver emulation, we're dealing with a GL_TEXTURE_2D texture which
706 * has the address mode set to repeat - something that prevents us
707 * from hitting the accelerated codepath. Thus manually set the GL
708 * state. The same applies to filtering. Even if the texture has only
709 * one mip level, the default LINEAR_MIPMAP_LINEAR filter causes a SW
710 * fallback on macos. */
711 gl_info
->gl_ops
.gl
.p_glTexParameteri(target
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
712 gl_info
->gl_ops
.gl
.p_glTexParameteri(target
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
713 gl_info
->gl_ops
.gl
.p_glTexParameteri(target
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
714 gl_info
->gl_ops
.gl
.p_glTexParameteri(target
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
715 checkGLcall("glTexParameteri");
716 gl_tex
->sampler_desc
.address_u
= WINED3D_TADDRESS_CLAMP
;
717 gl_tex
->sampler_desc
.address_v
= WINED3D_TADDRESS_CLAMP
;
718 gl_tex
->sampler_desc
.mag_filter
= WINED3D_TEXF_POINT
;
719 gl_tex
->sampler_desc
.min_filter
= WINED3D_TEXF_POINT
;
720 gl_tex
->sampler_desc
.mip_filter
= WINED3D_TEXF_NONE
;
723 if (gl_info
->supported
[WINED3D_GL_LEGACY_CONTEXT
] && gl_info
->supported
[ARB_DEPTH_TEXTURE
])
725 gl_info
->gl_ops
.gl
.p_glTexParameteri(target
, GL_DEPTH_TEXTURE_MODE_ARB
, GL_INTENSITY
);
726 checkGLcall("glTexParameteri(GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY)");
729 if (!is_identity_fixup(fixup
) && can_use_texture_swizzle(gl_info
, format
))
731 static const GLenum swizzle_source
[] =
733 GL_ZERO
, /* CHANNEL_SOURCE_ZERO */
734 GL_ONE
, /* CHANNEL_SOURCE_ONE */
735 GL_RED
, /* CHANNEL_SOURCE_X */
736 GL_GREEN
, /* CHANNEL_SOURCE_Y */
737 GL_BLUE
, /* CHANNEL_SOURCE_Z */
738 GL_ALPHA
, /* CHANNEL_SOURCE_W */
746 swizzle
.x
= swizzle_source
[fixup
.x_source
];
747 swizzle
.y
= swizzle_source
[fixup
.y_source
];
748 swizzle
.z
= swizzle_source
[fixup
.z_source
];
749 swizzle
.w
= swizzle_source
[fixup
.w_source
];
750 gl_info
->gl_ops
.gl
.p_glTexParameteriv(target
, GL_TEXTURE_SWIZZLE_RGBA
, &swizzle
.x
);
751 checkGLcall("glTexParameteriv(GL_TEXTURE_SWIZZLE_RGBA)");
755 /* Context activation is done by the caller. */
756 void wined3d_texture_bind_and_dirtify(struct wined3d_texture
*texture
,
757 struct wined3d_context
*context
, BOOL srgb
)
759 DWORD active_sampler
;
761 /* We don't need a specific texture unit, but after binding the texture
762 * the current unit is dirty. Read the unit back instead of switching to
763 * 0, this avoids messing around with the state manager's GL states. The
764 * current texture unit should always be a valid one.
766 * To be more specific, this is tricky because we can implicitly be
767 * called from sampler() in state.c. This means we can't touch anything
768 * other than whatever happens to be the currently active texture, or we
769 * would risk marking already applied sampler states dirty again. */
770 active_sampler
= context
->rev_tex_unit_map
[context
->active_texture
];
771 if (active_sampler
!= WINED3D_UNMAPPED_STAGE
)
772 context_invalidate_state(context
, STATE_SAMPLER(active_sampler
));
773 /* FIXME: Ideally we'd only do this when touching a binding that's used by
775 context_invalidate_state(context
, STATE_SHADER_RESOURCE_BINDING
);
777 wined3d_texture_bind(texture
, context
, srgb
);
780 /* Context activation is done by the caller (state handler). */
781 /* This function relies on the correct texture being bound and loaded. */
782 void wined3d_texture_apply_sampler_desc(struct wined3d_texture
*texture
,
783 const struct wined3d_sampler_desc
*sampler_desc
, const struct wined3d_context
*context
)
785 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
786 GLenum target
= texture
->target
;
787 struct gl_texture
*gl_tex
;
790 TRACE("texture %p, sampler_desc %p, context %p.\n", texture
, sampler_desc
, context
);
792 gl_tex
= wined3d_texture_get_gl_texture(texture
, texture
->flags
& WINED3D_TEXTURE_IS_SRGB
);
794 state
= sampler_desc
->address_u
;
795 if (state
!= gl_tex
->sampler_desc
.address_u
)
797 gl_info
->gl_ops
.gl
.p_glTexParameteri(target
, GL_TEXTURE_WRAP_S
,
798 gl_info
->wrap_lookup
[state
- WINED3D_TADDRESS_WRAP
]);
799 gl_tex
->sampler_desc
.address_u
= state
;
802 state
= sampler_desc
->address_v
;
803 if (state
!= gl_tex
->sampler_desc
.address_v
)
805 gl_info
->gl_ops
.gl
.p_glTexParameteri(target
, GL_TEXTURE_WRAP_T
,
806 gl_info
->wrap_lookup
[state
- WINED3D_TADDRESS_WRAP
]);
807 gl_tex
->sampler_desc
.address_v
= state
;
810 state
= sampler_desc
->address_w
;
811 if (state
!= gl_tex
->sampler_desc
.address_w
)
813 gl_info
->gl_ops
.gl
.p_glTexParameteri(target
, GL_TEXTURE_WRAP_R
,
814 gl_info
->wrap_lookup
[state
- WINED3D_TADDRESS_WRAP
]);
815 gl_tex
->sampler_desc
.address_w
= state
;
818 if (memcmp(gl_tex
->sampler_desc
.border_color
, sampler_desc
->border_color
,
819 sizeof(gl_tex
->sampler_desc
.border_color
)))
821 gl_info
->gl_ops
.gl
.p_glTexParameterfv(target
, GL_TEXTURE_BORDER_COLOR
, &sampler_desc
->border_color
[0]);
822 memcpy(gl_tex
->sampler_desc
.border_color
, sampler_desc
->border_color
,
823 sizeof(gl_tex
->sampler_desc
.border_color
));
826 state
= sampler_desc
->mag_filter
;
827 if (state
!= gl_tex
->sampler_desc
.mag_filter
)
829 gl_info
->gl_ops
.gl
.p_glTexParameteri(target
, GL_TEXTURE_MAG_FILTER
, wined3d_gl_mag_filter(state
));
830 gl_tex
->sampler_desc
.mag_filter
= state
;
833 if (sampler_desc
->min_filter
!= gl_tex
->sampler_desc
.min_filter
834 || sampler_desc
->mip_filter
!= gl_tex
->sampler_desc
.mip_filter
)
836 gl_info
->gl_ops
.gl
.p_glTexParameteri(target
, GL_TEXTURE_MIN_FILTER
,
837 wined3d_gl_min_mip_filter(sampler_desc
->min_filter
, sampler_desc
->mip_filter
));
838 gl_tex
->sampler_desc
.min_filter
= sampler_desc
->min_filter
;
839 gl_tex
->sampler_desc
.mip_filter
= sampler_desc
->mip_filter
;
842 state
= sampler_desc
->max_anisotropy
;
843 if (state
!= gl_tex
->sampler_desc
.max_anisotropy
)
845 if (gl_info
->supported
[EXT_TEXTURE_FILTER_ANISOTROPIC
])
846 gl_info
->gl_ops
.gl
.p_glTexParameteri(target
, GL_TEXTURE_MAX_ANISOTROPY_EXT
, state
);
848 WARN("Anisotropic filtering not supported.\n");
849 gl_tex
->sampler_desc
.max_anisotropy
= state
;
852 if (!sampler_desc
->srgb_decode
!= !gl_tex
->sampler_desc
.srgb_decode
853 && (context
->d3d_info
->wined3d_creation_flags
& WINED3D_SRGB_READ_WRITE_CONTROL
)
854 && gl_info
->supported
[EXT_TEXTURE_SRGB_DECODE
])
856 gl_info
->gl_ops
.gl
.p_glTexParameteri(target
, GL_TEXTURE_SRGB_DECODE_EXT
,
857 sampler_desc
->srgb_decode
? GL_DECODE_EXT
: GL_SKIP_DECODE_EXT
);
858 gl_tex
->sampler_desc
.srgb_decode
= sampler_desc
->srgb_decode
;
861 if (!sampler_desc
->compare
!= !gl_tex
->sampler_desc
.compare
)
863 if (sampler_desc
->compare
)
864 gl_info
->gl_ops
.gl
.p_glTexParameteri(target
, GL_TEXTURE_COMPARE_MODE_ARB
, GL_COMPARE_R_TO_TEXTURE_ARB
);
866 gl_info
->gl_ops
.gl
.p_glTexParameteri(target
, GL_TEXTURE_COMPARE_MODE_ARB
, GL_NONE
);
867 gl_tex
->sampler_desc
.compare
= sampler_desc
->compare
;
870 checkGLcall("Texture parameter application");
872 if (gl_info
->supported
[EXT_TEXTURE_LOD_BIAS
])
874 gl_info
->gl_ops
.gl
.p_glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT
,
875 GL_TEXTURE_LOD_BIAS_EXT
, sampler_desc
->lod_bias
);
876 checkGLcall("glTexEnvf(GL_TEXTURE_LOD_BIAS_EXT, ...)");
880 ULONG CDECL
wined3d_texture_incref(struct wined3d_texture
*texture
)
884 TRACE("texture %p, swapchain %p.\n", texture
, texture
->swapchain
);
886 if (texture
->swapchain
)
887 return wined3d_swapchain_incref(texture
->swapchain
);
889 refcount
= InterlockedIncrement(&texture
->resource
.ref
);
890 TRACE("%p increasing refcount to %u.\n", texture
, refcount
);
895 static void wined3d_texture_cleanup_sync(struct wined3d_texture
*texture
)
897 wined3d_texture_sub_resources_destroyed(texture
);
898 resource_cleanup(&texture
->resource
);
899 wined3d_resource_wait_idle(&texture
->resource
);
900 wined3d_texture_cleanup(texture
);
903 static void wined3d_texture_destroy_object(void *object
)
905 wined3d_texture_cleanup(object
);
906 HeapFree(GetProcessHeap(), 0, object
);
909 ULONG CDECL
wined3d_texture_decref(struct wined3d_texture
*texture
)
913 TRACE("texture %p, swapchain %p.\n", texture
, texture
->swapchain
);
915 if (texture
->swapchain
)
916 return wined3d_swapchain_decref(texture
->swapchain
);
918 refcount
= InterlockedDecrement(&texture
->resource
.ref
);
919 TRACE("%p decreasing refcount to %u.\n", texture
, refcount
);
923 /* Wait for the texture to become idle if it's using user memory,
924 * since the application is allowed to free that memory once the
925 * texture is destroyed. Note that this implies that
926 * wined3d_texture_destroy_object() can't access that memory either. */
927 if (texture
->user_memory
)
928 wined3d_resource_wait_idle(&texture
->resource
);
929 wined3d_texture_sub_resources_destroyed(texture
);
930 texture
->resource
.parent_ops
->wined3d_object_destroyed(texture
->resource
.parent
);
931 resource_cleanup(&texture
->resource
);
932 wined3d_cs_emit_destroy_object(texture
->resource
.device
->cs
, wined3d_texture_destroy_object
, texture
);
938 struct wined3d_resource
* CDECL
wined3d_texture_get_resource(struct wined3d_texture
*texture
)
940 TRACE("texture %p.\n", texture
);
942 return &texture
->resource
;
945 static BOOL
color_key_equal(const struct wined3d_color_key
*c1
, struct wined3d_color_key
*c2
)
947 return c1
->color_space_low_value
== c2
->color_space_low_value
948 && c1
->color_space_high_value
== c2
->color_space_high_value
;
951 /* Context activation is done by the caller */
952 void wined3d_texture_load(struct wined3d_texture
*texture
,
953 struct wined3d_context
*context
, BOOL srgb
)
955 UINT sub_count
= texture
->level_count
* texture
->layer_count
;
956 const struct wined3d_d3d_info
*d3d_info
= context
->d3d_info
;
960 TRACE("texture %p, context %p, srgb %#x.\n", texture
, context
, srgb
);
962 if (!needs_separate_srgb_gl_texture(context
, texture
))
966 flag
= WINED3D_TEXTURE_SRGB_VALID
;
968 flag
= WINED3D_TEXTURE_RGB_VALID
;
970 if (!d3d_info
->shader_color_key
971 && (!(texture
->async
.flags
& WINED3D_TEXTURE_ASYNC_COLOR_KEY
)
972 != !(texture
->async
.color_key_flags
& WINED3D_CKEY_SRC_BLT
)
973 || (texture
->async
.flags
& WINED3D_TEXTURE_ASYNC_COLOR_KEY
974 && !color_key_equal(&texture
->async
.gl_color_key
, &texture
->async
.src_blt_color_key
))))
976 unsigned int sub_count
= texture
->level_count
* texture
->layer_count
;
979 TRACE("Reloading because of color key value change.\n");
980 for (i
= 0; i
< sub_count
; i
++)
982 if (!wined3d_texture_load_location(texture
, i
, context
, texture
->resource
.map_binding
))
983 ERR("Failed to load location %s.\n", wined3d_debug_location(texture
->resource
.map_binding
));
985 wined3d_texture_invalidate_location(texture
, i
, ~texture
->resource
.map_binding
);
988 texture
->async
.gl_color_key
= texture
->async
.src_blt_color_key
;
991 if (texture
->flags
& flag
)
993 TRACE("Texture %p not dirty, nothing to do.\n", texture
);
997 /* Reload the surfaces if the texture is marked dirty. */
998 for (i
= 0; i
< sub_count
; ++i
)
1000 if (!wined3d_texture_load_location(texture
, i
, context
,
1001 srgb
? WINED3D_LOCATION_TEXTURE_SRGB
: WINED3D_LOCATION_TEXTURE_RGB
))
1002 ERR("Failed to load location (srgb %#x).\n", srgb
);
1004 texture
->flags
|= flag
;
1007 void * CDECL
wined3d_texture_get_parent(const struct wined3d_texture
*texture
)
1009 TRACE("texture %p.\n", texture
);
1011 return texture
->resource
.parent
;
1014 static BOOL
wined3d_texture_check_box_dimensions(const struct wined3d_texture
*texture
,
1015 unsigned int level
, const struct wined3d_box
*box
)
1017 if (box
->left
>= box
->right
1018 || box
->top
>= box
->bottom
1019 || box
->front
>= box
->back
)
1022 if (box
->right
> wined3d_texture_get_level_width(texture
, level
)
1023 || box
->bottom
> wined3d_texture_get_level_height(texture
, level
)
1024 || box
->back
> wined3d_texture_get_level_depth(texture
, level
))
1030 void CDECL
wined3d_texture_get_pitch(const struct wined3d_texture
*texture
,
1031 unsigned int level
, unsigned int *row_pitch
, unsigned int *slice_pitch
)
1033 const struct wined3d_resource
*resource
= &texture
->resource
;
1034 unsigned int width
= wined3d_texture_get_level_width(texture
, level
);
1035 unsigned int height
= wined3d_texture_get_level_height(texture
, level
);
1037 if (texture
->row_pitch
)
1039 *row_pitch
= texture
->row_pitch
;
1040 *slice_pitch
= texture
->slice_pitch
;
1044 wined3d_format_calculate_pitch(resource
->format
, resource
->device
->surface_alignment
,
1045 width
, height
, row_pitch
, slice_pitch
);
1048 DWORD CDECL
wined3d_texture_set_lod(struct wined3d_texture
*texture
, DWORD lod
)
1050 DWORD old
= texture
->lod
;
1052 TRACE("texture %p, lod %u.\n", texture
, lod
);
1054 /* The d3d9:texture test shows that SetLOD is ignored on non-managed
1055 * textures. The call always returns 0, and GetLOD always returns 0. */
1056 if (texture
->resource
.pool
!= WINED3D_POOL_MANAGED
)
1058 TRACE("Ignoring SetLOD on %s texture, returning 0.\n", debug_d3dpool(texture
->resource
.pool
));
1062 if (lod
>= texture
->level_count
)
1063 lod
= texture
->level_count
- 1;
1065 if (texture
->lod
!= lod
)
1067 wined3d_resource_wait_idle(&texture
->resource
);
1070 texture
->texture_rgb
.base_level
= ~0u;
1071 texture
->texture_srgb
.base_level
= ~0u;
1072 if (texture
->resource
.bind_count
)
1073 device_invalidate_state(texture
->resource
.device
, STATE_SAMPLER(texture
->sampler
));
1079 DWORD CDECL
wined3d_texture_get_lod(const struct wined3d_texture
*texture
)
1081 TRACE("texture %p, returning %u.\n", texture
, texture
->lod
);
1083 return texture
->lod
;
1086 DWORD CDECL
wined3d_texture_get_level_count(const struct wined3d_texture
*texture
)
1088 TRACE("texture %p, returning %u.\n", texture
, texture
->level_count
);
1090 return texture
->level_count
;
1093 HRESULT CDECL
wined3d_texture_set_autogen_filter_type(struct wined3d_texture
*texture
,
1094 enum wined3d_texture_filter_type filter_type
)
1096 FIXME("texture %p, filter_type %s stub!\n", texture
, debug_d3dtexturefiltertype(filter_type
));
1098 if (!(texture
->resource
.usage
& WINED3DUSAGE_AUTOGENMIPMAP
))
1100 WARN("Texture doesn't have AUTOGENMIPMAP usage.\n");
1101 return WINED3DERR_INVALIDCALL
;
1104 texture
->filter_type
= filter_type
;
1109 enum wined3d_texture_filter_type CDECL
wined3d_texture_get_autogen_filter_type(const struct wined3d_texture
*texture
)
1111 TRACE("texture %p.\n", texture
);
1113 return texture
->filter_type
;
1116 HRESULT CDECL
wined3d_texture_set_color_key(struct wined3d_texture
*texture
,
1117 DWORD flags
, const struct wined3d_color_key
*color_key
)
1119 struct wined3d_device
*device
= texture
->resource
.device
;
1120 static const DWORD all_flags
= WINED3D_CKEY_DST_BLT
| WINED3D_CKEY_DST_OVERLAY
1121 | WINED3D_CKEY_SRC_BLT
| WINED3D_CKEY_SRC_OVERLAY
;
1123 TRACE("texture %p, flags %#x, color_key %p.\n", texture
, flags
, color_key
);
1125 if (flags
& ~all_flags
)
1127 WARN("Invalid flags passed, returning WINED3DERR_INVALIDCALL.\n");
1128 return WINED3DERR_INVALIDCALL
;
1131 wined3d_cs_emit_set_color_key(device
->cs
, texture
, flags
, color_key
);
1136 HRESULT CDECL
wined3d_texture_update_desc(struct wined3d_texture
*texture
, UINT width
, UINT height
,
1137 enum wined3d_format_id format_id
, enum wined3d_multisample_type multisample_type
,
1138 UINT multisample_quality
, void *mem
, UINT pitch
)
1140 struct wined3d_device
*device
= texture
->resource
.device
;
1141 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
1142 const struct wined3d_format
*format
= wined3d_get_format(gl_info
, format_id
, texture
->resource
.usage
);
1143 UINT resource_size
= wined3d_format_calculate_size(format
, device
->surface_alignment
, width
, height
, 1);
1144 struct wined3d_texture_sub_resource
*sub_resource
;
1145 struct wined3d_surface
*surface
;
1146 DWORD valid_location
= 0;
1147 BOOL create_dib
= FALSE
;
1149 TRACE("texture %p, width %u, height %u, format %s, multisample_type %#x, multisample_quality %u, "
1150 "mem %p, pitch %u.\n",
1151 texture
, width
, height
, debug_d3dformat(format_id
), multisample_type
, multisample_quality
, mem
, pitch
);
1154 return WINED3DERR_INVALIDCALL
;
1156 if (texture
->level_count
* texture
->layer_count
> 1)
1158 WARN("Texture has multiple sub-resources, not supported.\n");
1159 return WINED3DERR_INVALIDCALL
;
1162 if (texture
->resource
.type
== WINED3D_RTYPE_TEXTURE_3D
)
1164 WARN("Not supported on 3D textures.\n");
1165 return WINED3DERR_INVALIDCALL
;
1168 if (texture
->resource
.map_count
)
1170 WARN("Texture is mapped.\n");
1171 return WINED3DERR_INVALIDCALL
;
1174 /* We have no way of supporting a pitch that is not a multiple of the pixel
1175 * byte width short of uploading the texture row-by-row.
1176 * Fortunately that's not an issue since D3D9Ex doesn't allow a custom pitch
1177 * for user-memory textures (it always expects packed data) while DirectDraw
1178 * requires a 4-byte aligned pitch and doesn't support texture formats
1179 * larger than 4 bytes per pixel nor any format using 3 bytes per pixel.
1180 * This check is here to verify that the assumption holds. */
1181 if (pitch
% texture
->resource
.format
->byte_count
)
1183 WARN("Pitch unsupported, not a multiple of the texture format byte width.\n");
1184 return WINED3DERR_INVALIDCALL
;
1187 if (device
->d3d_initialized
)
1188 wined3d_cs_emit_unload_resource(device
->cs
, &texture
->resource
);
1189 wined3d_resource_wait_idle(&texture
->resource
);
1191 sub_resource
= &texture
->sub_resources
[0];
1192 surface
= sub_resource
->u
.surface
;
1195 wined3d_surface_destroy_dc(surface
);
1199 wined3d_resource_free_sysmem(&texture
->resource
);
1201 if ((texture
->row_pitch
= pitch
))
1202 texture
->slice_pitch
= height
* pitch
;
1204 /* User memory surfaces don't have the regular surface alignment. */
1205 wined3d_format_calculate_pitch(format
, 1, width
, height
,
1206 &texture
->row_pitch
, &texture
->slice_pitch
);
1208 texture
->resource
.format
= format
;
1209 texture
->resource
.multisample_type
= multisample_type
;
1210 texture
->resource
.multisample_quality
= multisample_quality
;
1211 texture
->resource
.width
= width
;
1212 texture
->resource
.height
= height
;
1213 texture
->resource
.size
= texture
->slice_pitch
;
1214 sub_resource
->size
= texture
->slice_pitch
;
1215 sub_resource
->locations
= WINED3D_LOCATION_DISCARDED
;
1217 if (((width
& (width
- 1)) || (height
& (height
- 1))) && !gl_info
->supported
[ARB_TEXTURE_NON_POWER_OF_TWO
]
1218 && !gl_info
->supported
[ARB_TEXTURE_RECTANGLE
] && !gl_info
->supported
[WINED3D_GL_NORMALIZED_TEXRECT
])
1220 texture
->flags
|= WINED3D_TEXTURE_COND_NP2_EMULATED
;
1221 texture
->pow2_width
= texture
->pow2_height
= 1;
1222 while (texture
->pow2_width
< width
)
1223 texture
->pow2_width
<<= 1;
1224 while (texture
->pow2_height
< height
)
1225 texture
->pow2_height
<<= 1;
1229 texture
->flags
&= ~WINED3D_TEXTURE_COND_NP2_EMULATED
;
1230 texture
->pow2_width
= width
;
1231 texture
->pow2_height
= height
;
1234 if ((texture
->user_memory
= mem
))
1236 texture
->resource
.map_binding
= WINED3D_LOCATION_USER_MEMORY
;
1237 valid_location
= WINED3D_LOCATION_USER_MEMORY
;
1241 wined3d_texture_prepare_location(texture
, 0, NULL
, WINED3D_LOCATION_SYSMEM
);
1242 valid_location
= WINED3D_LOCATION_SYSMEM
;
1245 /* The format might be changed to a format that needs conversion.
1246 * If the surface didn't use PBOs previously but could now, don't
1247 * change it - whatever made us not use PBOs might come back, e.g.
1249 if (texture
->resource
.map_binding
== WINED3D_LOCATION_BUFFER
&& !wined3d_texture_use_pbo(texture
, gl_info
))
1250 texture
->resource
.map_binding
= WINED3D_LOCATION_SYSMEM
;
1252 wined3d_texture_validate_location(texture
, 0, valid_location
);
1253 wined3d_texture_invalidate_location(texture
, 0, ~valid_location
);
1256 wined3d_surface_create_dc(surface
);
1261 /* Context activation is done by the caller. */
1262 static void wined3d_texture_prepare_buffer_object(struct wined3d_texture
*texture
,
1263 unsigned int sub_resource_idx
, const struct wined3d_gl_info
*gl_info
)
1265 struct wined3d_texture_sub_resource
*sub_resource
;
1267 sub_resource
= &texture
->sub_resources
[sub_resource_idx
];
1268 if (sub_resource
->buffer_object
)
1271 GL_EXTCALL(glGenBuffers(1, &sub_resource
->buffer_object
));
1272 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, sub_resource
->buffer_object
));
1273 GL_EXTCALL(glBufferData(GL_PIXEL_UNPACK_BUFFER
, sub_resource
->size
, NULL
, GL_STREAM_DRAW
));
1274 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, 0));
1275 checkGLcall("Create buffer object");
1277 TRACE("Created buffer object %u for texture %p, sub-resource %u.\n",
1278 sub_resource
->buffer_object
, texture
, sub_resource_idx
);
1281 static void wined3d_texture_force_reload(struct wined3d_texture
*texture
)
1283 unsigned int sub_count
= texture
->level_count
* texture
->layer_count
;
1286 texture
->flags
&= ~(WINED3D_TEXTURE_RGB_ALLOCATED
| WINED3D_TEXTURE_SRGB_ALLOCATED
1287 | WINED3D_TEXTURE_CONVERTED
);
1288 texture
->async
.flags
&= ~WINED3D_TEXTURE_ASYNC_COLOR_KEY
;
1289 for (i
= 0; i
< sub_count
; ++i
)
1291 wined3d_texture_invalidate_location(texture
, i
,
1292 WINED3D_LOCATION_TEXTURE_RGB
| WINED3D_LOCATION_TEXTURE_SRGB
);
1296 void wined3d_texture_prepare_texture(struct wined3d_texture
*texture
, struct wined3d_context
*context
, BOOL srgb
)
1298 DWORD alloc_flag
= srgb
? WINED3D_TEXTURE_SRGB_ALLOCATED
: WINED3D_TEXTURE_RGB_ALLOCATED
;
1299 const struct wined3d_d3d_info
*d3d_info
= context
->d3d_info
;
1301 if (!d3d_info
->shader_color_key
1302 && !(texture
->async
.flags
& WINED3D_TEXTURE_ASYNC_COLOR_KEY
)
1303 != !(texture
->async
.color_key_flags
& WINED3D_CKEY_SRC_BLT
))
1305 wined3d_texture_force_reload(texture
);
1307 if (texture
->async
.color_key_flags
& WINED3D_CKEY_SRC_BLT
)
1308 texture
->async
.flags
|= WINED3D_TEXTURE_ASYNC_COLOR_KEY
;
1311 if (texture
->flags
& alloc_flag
)
1314 texture
->texture_ops
->texture_prepare_texture(texture
, context
, srgb
);
1315 texture
->flags
|= alloc_flag
;
1318 static void wined3d_texture_prepare_rb(struct wined3d_texture
*texture
,
1319 const struct wined3d_gl_info
*gl_info
, BOOL multisample
)
1321 const struct wined3d_format
*format
= texture
->resource
.format
;
1327 if (texture
->rb_multisample
)
1330 /* TODO: NVIDIA expose their Coverage Sample Anti-Aliasing (CSAA)
1331 * feature through type == MULTISAMPLE_XX and quality != 0. This could
1332 * be mapped to GL_NV_framebuffer_multisample_coverage.
1334 * AMD have a similar feature called Enhanced Quality Anti-Aliasing
1335 * (EQAA), but it does not have an equivalent OpenGL extension. */
1337 /* We advertise as many WINED3D_MULTISAMPLE_NON_MASKABLE quality
1338 * levels as the count of advertised multisample types for the texture
1340 if (texture
->resource
.multisample_type
== WINED3D_MULTISAMPLE_NON_MASKABLE
)
1342 unsigned int i
, count
= 0;
1344 for (i
= 0; i
< sizeof(format
->multisample_types
) * 8; ++i
)
1346 if (format
->multisample_types
& 1u << i
)
1348 if (texture
->resource
.multisample_quality
== count
++)
1356 samples
= texture
->resource
.multisample_type
;
1359 gl_info
->fbo_ops
.glGenRenderbuffers(1, &texture
->rb_multisample
);
1360 gl_info
->fbo_ops
.glBindRenderbuffer(GL_RENDERBUFFER
, texture
->rb_multisample
);
1361 gl_info
->fbo_ops
.glRenderbufferStorageMultisample(GL_RENDERBUFFER
, samples
,
1362 format
->glInternal
, texture
->resource
.width
, texture
->resource
.height
);
1363 checkGLcall("glRenderbufferStorageMultisample()");
1364 TRACE("Created multisample rb %u.\n", texture
->rb_multisample
);
1368 if (texture
->rb_resolved
)
1371 gl_info
->fbo_ops
.glGenRenderbuffers(1, &texture
->rb_resolved
);
1372 gl_info
->fbo_ops
.glBindRenderbuffer(GL_RENDERBUFFER
, texture
->rb_resolved
);
1373 gl_info
->fbo_ops
.glRenderbufferStorage(GL_RENDERBUFFER
, format
->glInternal
,
1374 texture
->resource
.width
, texture
->resource
.height
);
1375 checkGLcall("glRenderbufferStorage()");
1376 TRACE("Created resolved rb %u.\n", texture
->rb_resolved
);
1380 /* Context activation is done by the caller. Context may be NULL in
1381 * WINED3D_NO3D mode. */
1382 BOOL
wined3d_texture_prepare_location(struct wined3d_texture
*texture
, unsigned int sub_resource_idx
,
1383 struct wined3d_context
*context
, DWORD location
)
1387 case WINED3D_LOCATION_SYSMEM
:
1388 if (texture
->resource
.heap_memory
)
1391 if (!wined3d_resource_allocate_sysmem(&texture
->resource
))
1393 ERR("Failed to allocate system memory.\n");
1398 case WINED3D_LOCATION_USER_MEMORY
:
1399 if (!texture
->user_memory
)
1400 ERR("Map binding is set to WINED3D_LOCATION_USER_MEMORY but surface->user_memory is NULL.\n");
1403 case WINED3D_LOCATION_BUFFER
:
1404 wined3d_texture_prepare_buffer_object(texture
, sub_resource_idx
, context
->gl_info
);
1407 case WINED3D_LOCATION_TEXTURE_RGB
:
1408 wined3d_texture_prepare_texture(texture
, context
, FALSE
);
1411 case WINED3D_LOCATION_TEXTURE_SRGB
:
1412 wined3d_texture_prepare_texture(texture
, context
, TRUE
);
1415 case WINED3D_LOCATION_DRAWABLE
:
1416 if (!texture
->swapchain
&& wined3d_settings
.offscreen_rendering_mode
!= ORM_BACKBUFFER
)
1417 ERR("Texture %p does not have a drawable.\n", texture
);
1420 case WINED3D_LOCATION_RB_MULTISAMPLE
:
1421 wined3d_texture_prepare_rb(texture
, context
->gl_info
, TRUE
);
1424 case WINED3D_LOCATION_RB_RESOLVED
:
1425 wined3d_texture_prepare_rb(texture
, context
->gl_info
, FALSE
);
1429 ERR("Invalid location %s.\n", wined3d_debug_location(location
));
1434 void CDECL
wined3d_texture_generate_mipmaps(struct wined3d_texture
*texture
)
1436 /* TODO: Implement filters using GL_SGI_generate_mipmaps. */
1437 FIXME("texture %p stub!\n", texture
);
1440 static struct wined3d_texture_sub_resource
*wined3d_texture_get_sub_resource(struct wined3d_texture
*texture
,
1441 unsigned int sub_resource_idx
)
1443 UINT sub_count
= texture
->level_count
* texture
->layer_count
;
1445 TRACE("texture %p, sub_resource_idx %u.\n", texture
, sub_resource_idx
);
1447 if (sub_resource_idx
>= sub_count
)
1449 WARN("sub_resource_idx %u >= sub_count %u.\n", sub_resource_idx
, sub_count
);
1453 return &texture
->sub_resources
[sub_resource_idx
];
1456 HRESULT CDECL
wined3d_texture_add_dirty_region(struct wined3d_texture
*texture
,
1457 UINT layer
, const struct wined3d_box
*dirty_region
)
1459 struct wined3d_context
*context
;
1460 unsigned int sub_resource_idx
;
1462 TRACE("texture %p, layer %u, dirty_region %s.\n", texture
, layer
, debug_box(dirty_region
));
1464 if (layer
>= texture
->layer_count
)
1466 WARN("Invalid layer %u specified.\n", layer
);
1467 return WINED3DERR_INVALIDCALL
;
1469 sub_resource_idx
= layer
* texture
->level_count
;
1472 FIXME("Ignoring dirty_region %s.\n", debug_box(dirty_region
));
1474 context
= context_acquire(texture
->resource
.device
, NULL
);
1475 if (!wined3d_texture_load_location(texture
, sub_resource_idx
, context
, texture
->resource
.map_binding
))
1477 ERR("Failed to load location %s.\n", wined3d_debug_location(texture
->resource
.map_binding
));
1478 context_release(context
);
1479 return E_OUTOFMEMORY
;
1481 wined3d_texture_invalidate_location(texture
, sub_resource_idx
, ~texture
->resource
.map_binding
);
1482 context_release(context
);
1487 void wined3d_texture_upload_data(struct wined3d_texture
*texture
, unsigned int sub_resource_idx
,
1488 const struct wined3d_context
*context
, const struct wined3d_box
*box
,
1489 const struct wined3d_const_bo_address
*data
, unsigned int row_pitch
, unsigned int slice_pitch
)
1491 texture
->texture_ops
->texture_upload_data(texture
, sub_resource_idx
,
1492 context
, box
, data
, row_pitch
, slice_pitch
);
1495 static void texture2d_upload_data(struct wined3d_texture
*texture
, unsigned int sub_resource_idx
,
1496 const struct wined3d_context
*context
, const struct wined3d_box
*box
,
1497 const struct wined3d_const_bo_address
*data
, unsigned int row_pitch
, unsigned int slice_pitch
)
1499 unsigned int texture_level
;
1507 dst_point
.x
= box
->left
;
1508 dst_point
.y
= box
->top
;
1509 src_rect
.right
= box
->right
- box
->left
;
1510 src_rect
.bottom
= box
->bottom
- box
->top
;
1514 dst_point
.x
= dst_point
.y
= 0;
1515 texture_level
= sub_resource_idx
% texture
->level_count
;
1516 src_rect
.right
= wined3d_texture_get_level_width(texture
, texture_level
);
1517 src_rect
.bottom
= wined3d_texture_get_level_height(texture
, texture_level
);
1520 wined3d_surface_upload_data(texture
->sub_resources
[sub_resource_idx
].u
.surface
, context
->gl_info
,
1521 texture
->resource
.format
, &src_rect
, row_pitch
, &dst_point
, FALSE
, data
);
1524 static BOOL
texture2d_load_location(struct wined3d_texture
*texture
, unsigned int sub_resource_idx
,
1525 struct wined3d_context
*context
, DWORD location
)
1527 return SUCCEEDED(surface_load_location(texture
->sub_resources
[sub_resource_idx
].u
.surface
, context
, location
));
1530 /* Context activation is done by the caller. */
1531 static void texture2d_prepare_texture(struct wined3d_texture
*texture
, struct wined3d_context
*context
, BOOL srgb
)
1533 const struct wined3d_format
*format
= texture
->resource
.format
;
1534 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
1535 const struct wined3d_color_key_conversion
*conversion
;
1538 TRACE("texture %p, context %p, format %s.\n", texture
, context
, debug_d3dformat(format
->id
));
1540 if (format
->convert
)
1542 texture
->flags
|= WINED3D_TEXTURE_CONVERTED
;
1544 else if ((conversion
= wined3d_format_get_color_key_conversion(texture
, TRUE
)))
1546 texture
->flags
|= WINED3D_TEXTURE_CONVERTED
;
1547 format
= wined3d_get_format(gl_info
, conversion
->dst_format
, texture
->resource
.usage
);
1548 TRACE("Using format %s for color key conversion.\n", debug_d3dformat(format
->id
));
1551 wined3d_texture_bind_and_dirtify(texture
, context
, srgb
);
1554 internal
= format
->glGammaInternal
;
1555 else if (texture
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
1556 && wined3d_resource_is_offscreen(&texture
->resource
))
1557 internal
= format
->rtInternal
;
1559 internal
= format
->glInternal
;
1562 FIXME("No GL internal format for format %s.\n", debug_d3dformat(format
->id
));
1564 TRACE("internal %#x, format %#x, type %#x.\n", internal
, format
->glFormat
, format
->glType
);
1566 if (wined3d_texture_use_immutable_storage(texture
, gl_info
))
1567 wined3d_texture_allocate_gl_immutable_storage(texture
, internal
, gl_info
);
1569 wined3d_texture_allocate_gl_mutable_storage(texture
, internal
, format
, gl_info
);
1572 static void texture2d_cleanup_sub_resources(struct wined3d_texture
*texture
)
1574 unsigned int sub_count
= texture
->level_count
* texture
->layer_count
;
1575 struct wined3d_device
*device
= texture
->resource
.device
;
1576 struct wined3d_texture_sub_resource
*sub_resource
;
1577 struct wined3d_renderbuffer_entry
*entry
, *entry2
;
1578 const struct wined3d_gl_info
*gl_info
= NULL
;
1579 struct wined3d_context
*context
= NULL
;
1580 struct wined3d_surface
*overlay
, *cur
;
1581 struct wined3d_surface
*surface
;
1584 for (i
= 0; i
< sub_count
; ++i
)
1586 sub_resource
= &texture
->sub_resources
[i
];
1587 if (!(surface
= sub_resource
->u
.surface
))
1590 TRACE("surface %p.\n", surface
);
1592 if (!context
&& !list_empty(&surface
->renderbuffers
))
1594 context
= context_acquire(device
, NULL
);
1595 gl_info
= context
->gl_info
;
1598 LIST_FOR_EACH_ENTRY_SAFE(entry
, entry2
, &surface
->renderbuffers
, struct wined3d_renderbuffer_entry
, entry
)
1600 TRACE("Deleting renderbuffer %u.\n", entry
->id
);
1601 context_gl_resource_released(device
, entry
->id
, TRUE
);
1602 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &entry
->id
);
1603 HeapFree(GetProcessHeap(), 0, entry
);
1607 wined3d_surface_destroy_dc(surface
);
1609 if (surface
->overlay_dest
)
1610 list_remove(&surface
->overlay_entry
);
1612 LIST_FOR_EACH_ENTRY_SAFE(overlay
, cur
, &surface
->overlays
, struct wined3d_surface
, overlay_entry
)
1614 list_remove(&overlay
->overlay_entry
);
1615 overlay
->overlay_dest
= NULL
;
1619 context_release(context
);
1620 HeapFree(GetProcessHeap(), 0, texture
->sub_resources
[0].u
.surface
);
1623 static const struct wined3d_texture_ops texture2d_ops
=
1625 texture2d_upload_data
,
1626 texture2d_load_location
,
1627 texture2d_prepare_texture
,
1628 texture2d_cleanup_sub_resources
,
1631 struct wined3d_texture
* __cdecl
wined3d_texture_from_resource(struct wined3d_resource
*resource
)
1633 return texture_from_resource(resource
);
1636 static ULONG
texture_resource_incref(struct wined3d_resource
*resource
)
1638 return wined3d_texture_incref(texture_from_resource(resource
));
1641 static ULONG
texture_resource_decref(struct wined3d_resource
*resource
)
1643 return wined3d_texture_decref(texture_from_resource(resource
));
1646 static void texture_resource_preload(struct wined3d_resource
*resource
)
1648 struct wined3d_texture
*texture
= texture_from_resource(resource
);
1649 struct wined3d_context
*context
;
1651 context
= context_acquire(resource
->device
, NULL
);
1652 wined3d_texture_load(texture
, context
, texture
->flags
& WINED3D_TEXTURE_IS_SRGB
);
1653 context_release(context
);
1656 static void wined3d_texture_unload(struct wined3d_resource
*resource
)
1658 struct wined3d_texture
*texture
= texture_from_resource(resource
);
1659 UINT sub_count
= texture
->level_count
* texture
->layer_count
;
1660 struct wined3d_device
*device
= resource
->device
;
1661 const struct wined3d_gl_info
*gl_info
;
1662 struct wined3d_context
*context
;
1665 TRACE("texture %p.\n", texture
);
1667 context
= context_acquire(device
, NULL
);
1668 gl_info
= context
->gl_info
;
1670 for (i
= 0; i
< sub_count
; ++i
)
1672 struct wined3d_texture_sub_resource
*sub_resource
= &texture
->sub_resources
[i
];
1674 if (resource
->pool
!= WINED3D_POOL_DEFAULT
1675 && wined3d_texture_load_location(texture
, i
, context
, resource
->map_binding
))
1677 wined3d_texture_invalidate_location(texture
, i
, ~resource
->map_binding
);
1681 /* We should only get here on device reset/teardown for implicit
1683 if (resource
->pool
!= WINED3D_POOL_DEFAULT
|| resource
->type
!= WINED3D_RTYPE_TEXTURE_2D
)
1684 ERR("Discarding %s %p sub-resource %u in the %s pool.\n", debug_d3dresourcetype(resource
->type
),
1685 resource
, i
, debug_d3dpool(resource
->pool
));
1686 wined3d_texture_validate_location(texture
, i
, WINED3D_LOCATION_DISCARDED
);
1687 wined3d_texture_invalidate_location(texture
, i
, ~WINED3D_LOCATION_DISCARDED
);
1690 if (sub_resource
->buffer_object
)
1691 wined3d_texture_remove_buffer_object(texture
, i
, context
->gl_info
);
1693 if (resource
->type
== WINED3D_RTYPE_TEXTURE_2D
)
1695 struct wined3d_surface
*surface
= sub_resource
->u
.surface
;
1696 struct wined3d_renderbuffer_entry
*entry
, *entry2
;
1698 LIST_FOR_EACH_ENTRY_SAFE(entry
, entry2
, &surface
->renderbuffers
, struct wined3d_renderbuffer_entry
, entry
)
1700 context_gl_resource_released(device
, entry
->id
, TRUE
);
1701 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &entry
->id
);
1702 list_remove(&entry
->entry
);
1703 HeapFree(GetProcessHeap(), 0, entry
);
1705 list_init(&surface
->renderbuffers
);
1706 surface
->current_renderbuffer
= NULL
;
1710 context_release(context
);
1712 wined3d_texture_force_reload(texture
);
1713 wined3d_texture_unload_gl_texture(texture
);
1716 static HRESULT
texture_resource_sub_resource_map(struct wined3d_resource
*resource
, unsigned int sub_resource_idx
,
1717 struct wined3d_map_desc
*map_desc
, const struct wined3d_box
*box
, DWORD flags
)
1719 const struct wined3d_format
*format
= resource
->format
;
1720 struct wined3d_texture_sub_resource
*sub_resource
;
1721 struct wined3d_device
*device
= resource
->device
;
1722 unsigned int fmt_flags
= resource
->format_flags
;
1723 const struct wined3d_gl_info
*gl_info
= NULL
;
1724 struct wined3d_context
*context
= NULL
;
1725 struct wined3d_texture
*texture
;
1726 struct wined3d_bo_address data
;
1727 unsigned int texture_level
;
1731 TRACE("resource %p, sub_resource_idx %u, map_desc %p, box %s, flags %#x.\n",
1732 resource
, sub_resource_idx
, map_desc
, debug_box(box
), flags
);
1734 texture
= texture_from_resource(resource
);
1735 if (!(sub_resource
= wined3d_texture_get_sub_resource(texture
, sub_resource_idx
)))
1736 return E_INVALIDARG
;
1738 texture_level
= sub_resource_idx
% texture
->level_count
;
1739 if (box
&& !wined3d_texture_check_box_dimensions(texture
, texture_level
, box
))
1741 WARN("Map box is invalid.\n");
1742 if (resource
->type
!= WINED3D_RTYPE_TEXTURE_2D
)
1743 return WINED3DERR_INVALIDCALL
;
1746 if ((fmt_flags
& WINED3DFMT_FLAG_BLOCKS
) && box
1747 && !wined3d_texture_check_block_align(texture
, texture_level
, box
))
1749 WARN("Map box %s is misaligned for %ux%u blocks.\n",
1750 debug_box(box
), format
->block_width
, format
->block_height
);
1751 if (resource
->type
!= WINED3D_RTYPE_TEXTURE_2D
|| resource
->pool
== WINED3D_POOL_DEFAULT
)
1752 return WINED3DERR_INVALIDCALL
;
1755 if (!(resource
->access_flags
& WINED3D_RESOURCE_ACCESS_CPU
))
1757 WARN("Trying to map unmappable texture.\n");
1758 if (resource
->type
!= WINED3D_RTYPE_TEXTURE_2D
)
1759 return WINED3DERR_INVALIDCALL
;
1762 if (texture
->flags
& WINED3D_TEXTURE_DC_IN_USE
)
1764 WARN("DC is in use.\n");
1765 return WINED3DERR_INVALIDCALL
;
1768 if (sub_resource
->map_count
)
1770 WARN("Sub-resource is already mapped.\n");
1771 return WINED3DERR_INVALIDCALL
;
1774 if (device
->d3d_initialized
)
1776 context
= context_acquire(device
, NULL
);
1777 gl_info
= context
->gl_info
;
1780 if (flags
& WINED3D_MAP_DISCARD
)
1782 TRACE("WINED3D_MAP_DISCARD flag passed, marking %s as up to date.\n",
1783 wined3d_debug_location(texture
->resource
.map_binding
));
1784 if ((ret
= wined3d_texture_prepare_location(texture
, sub_resource_idx
,
1785 context
, texture
->resource
.map_binding
)))
1786 wined3d_texture_validate_location(texture
, sub_resource_idx
, texture
->resource
.map_binding
);
1790 if (resource
->usage
& WINED3DUSAGE_DYNAMIC
)
1791 WARN_(d3d_perf
)("Mapping a dynamic texture without WINED3D_MAP_DISCARD.\n");
1792 ret
= wined3d_texture_load_location(texture
, sub_resource_idx
, context
, texture
->resource
.map_binding
);
1797 ERR("Failed to prepare location.\n");
1798 context_release(context
);
1799 return E_OUTOFMEMORY
;
1802 if (!(flags
& WINED3D_MAP_READONLY
)
1803 && (!(flags
& WINED3D_MAP_NO_DIRTY_UPDATE
) || (resource
->usage
& WINED3DUSAGE_DYNAMIC
)))
1804 wined3d_texture_invalidate_location(texture
, sub_resource_idx
, ~texture
->resource
.map_binding
);
1806 wined3d_texture_get_memory(texture
, sub_resource_idx
, &data
, texture
->resource
.map_binding
);
1807 base_memory
= wined3d_texture_map_bo_address(&data
, sub_resource
->size
,
1808 gl_info
, GL_PIXEL_UNPACK_BUFFER
, flags
);
1809 TRACE("Base memory pointer %p.\n", base_memory
);
1812 context_release(context
);
1814 if (fmt_flags
& WINED3DFMT_FLAG_BROKEN_PITCH
)
1816 map_desc
->row_pitch
= wined3d_texture_get_level_width(texture
, texture_level
) * format
->byte_count
;
1817 map_desc
->slice_pitch
= wined3d_texture_get_level_height(texture
, texture_level
) * map_desc
->row_pitch
;
1821 wined3d_texture_get_pitch(texture
, texture_level
, &map_desc
->row_pitch
, &map_desc
->slice_pitch
);
1826 map_desc
->data
= base_memory
;
1830 if ((fmt_flags
& (WINED3DFMT_FLAG_BLOCKS
| WINED3DFMT_FLAG_BROKEN_PITCH
)) == WINED3DFMT_FLAG_BLOCKS
)
1832 /* Compressed textures are block based, so calculate the offset of
1833 * the block that contains the top-left pixel of the mapped box. */
1834 map_desc
->data
= base_memory
1835 + (box
->front
* map_desc
->slice_pitch
)
1836 + ((box
->top
/ format
->block_height
) * map_desc
->row_pitch
)
1837 + ((box
->left
/ format
->block_width
) * format
->block_byte_count
);
1841 map_desc
->data
= base_memory
1842 + (box
->front
* map_desc
->slice_pitch
)
1843 + (box
->top
* map_desc
->row_pitch
)
1844 + (box
->left
* format
->byte_count
);
1848 if (texture
->swapchain
&& texture
->swapchain
->front_buffer
== texture
)
1850 RECT
*r
= &texture
->swapchain
->front_buffer_update
;
1853 SetRect(r
, 0, 0, resource
->width
, resource
->height
);
1855 SetRect(r
, box
->left
, box
->top
, box
->right
, box
->bottom
);
1856 TRACE("Mapped front buffer %s.\n", wine_dbgstr_rect(r
));
1859 ++resource
->map_count
;
1860 ++sub_resource
->map_count
;
1862 TRACE("Returning memory %p, row pitch %u, slice pitch %u.\n",
1863 map_desc
->data
, map_desc
->row_pitch
, map_desc
->slice_pitch
);
1868 static HRESULT
texture_resource_sub_resource_unmap(struct wined3d_resource
*resource
, unsigned int sub_resource_idx
)
1870 struct wined3d_texture_sub_resource
*sub_resource
;
1871 struct wined3d_device
*device
= resource
->device
;
1872 const struct wined3d_gl_info
*gl_info
= NULL
;
1873 struct wined3d_context
*context
= NULL
;
1874 struct wined3d_texture
*texture
;
1875 struct wined3d_bo_address data
;
1877 TRACE("resource %p, sub_resource_idx %u.\n", resource
, sub_resource_idx
);
1879 texture
= texture_from_resource(resource
);
1880 if (!(sub_resource
= wined3d_texture_get_sub_resource(texture
, sub_resource_idx
)))
1881 return E_INVALIDARG
;
1883 if (!sub_resource
->map_count
)
1885 WARN("Trying to unmap unmapped sub-resource.\n");
1886 if (texture
->flags
& WINED3D_TEXTURE_DC_IN_USE
)
1888 return WINEDDERR_NOTLOCKED
;
1891 if (device
->d3d_initialized
)
1893 context
= context_acquire(device
, NULL
);
1894 gl_info
= context
->gl_info
;
1897 wined3d_texture_get_memory(texture
, sub_resource_idx
, &data
, texture
->resource
.map_binding
);
1898 wined3d_texture_unmap_bo_address(&data
, gl_info
, GL_PIXEL_UNPACK_BUFFER
);
1901 context_release(context
);
1903 if (texture
->swapchain
&& texture
->swapchain
->front_buffer
== texture
)
1905 if (!(sub_resource
->locations
& (WINED3D_LOCATION_DRAWABLE
| WINED3D_LOCATION_TEXTURE_RGB
)))
1906 texture
->swapchain
->swapchain_ops
->swapchain_frontbuffer_updated(texture
->swapchain
);
1908 else if (resource
->format_flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
))
1910 FIXME("Depth / stencil buffer locking is not implemented.\n");
1913 --sub_resource
->map_count
;
1914 if (!--resource
->map_count
&& texture
->update_map_binding
)
1915 wined3d_texture_update_map_binding(texture
);
1920 static const struct wined3d_resource_ops texture_resource_ops
=
1922 texture_resource_incref
,
1923 texture_resource_decref
,
1924 texture_resource_preload
,
1925 wined3d_texture_unload
,
1926 texture_resource_sub_resource_map
,
1927 texture_resource_sub_resource_unmap
,
1930 static HRESULT
texture_init(struct wined3d_texture
*texture
, const struct wined3d_resource_desc
*desc
,
1931 unsigned int layer_count
, unsigned int level_count
, DWORD flags
, struct wined3d_device
*device
,
1932 void *parent
, const struct wined3d_parent_ops
*parent_ops
)
1934 struct wined3d_device_parent
*device_parent
= device
->device_parent
;
1935 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
1936 struct wined3d_surface
*surfaces
;
1937 UINT pow2_width
, pow2_height
;
1941 if (!(desc
->usage
& WINED3DUSAGE_LEGACY_CUBEMAP
) && layer_count
> 1
1942 && !gl_info
->supported
[EXT_TEXTURE_ARRAY
])
1944 WARN("OpenGL implementation does not support array textures.\n");
1945 return WINED3DERR_INVALIDCALL
;
1948 /* TODO: It should only be possible to create textures for formats
1949 * that are reported as supported. */
1950 if (WINED3DFMT_UNKNOWN
>= desc
->format
)
1952 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN.\n", texture
);
1953 return WINED3DERR_INVALIDCALL
;
1956 if (desc
->usage
& WINED3DUSAGE_DYNAMIC
&& desc
->pool
== WINED3D_POOL_MANAGED
)
1957 FIXME("Trying to create a managed texture with dynamic usage.\n");
1958 if (!(desc
->usage
& (WINED3DUSAGE_DYNAMIC
| WINED3DUSAGE_RENDERTARGET
| WINED3DUSAGE_DEPTHSTENCIL
))
1959 && (flags
& WINED3D_TEXTURE_CREATE_MAPPABLE
))
1960 WARN("Creating a mappable texture in the default pool that doesn't specify dynamic usage.\n");
1961 if (desc
->usage
& WINED3DUSAGE_RENDERTARGET
&& desc
->pool
!= WINED3D_POOL_DEFAULT
)
1962 FIXME("Trying to create a render target that isn't in the default pool.\n");
1964 pow2_width
= desc
->width
;
1965 pow2_height
= desc
->height
;
1966 if (((desc
->width
& (desc
->width
- 1)) || (desc
->height
& (desc
->height
- 1)))
1967 && !gl_info
->supported
[ARB_TEXTURE_NON_POWER_OF_TWO
])
1969 /* level_count == 0 returns an error as well. */
1970 if (level_count
!= 1 || layer_count
!= 1)
1972 if (desc
->pool
!= WINED3D_POOL_SCRATCH
)
1974 WARN("Attempted to create a mipmapped/cube/array NPOT texture without unconditional NPOT support.\n");
1975 return WINED3DERR_INVALIDCALL
;
1978 WARN("Creating a scratch mipmapped/cube/array NPOT texture despite lack of HW support.\n");
1980 texture
->flags
|= WINED3D_TEXTURE_COND_NP2
;
1982 if (!gl_info
->supported
[ARB_TEXTURE_RECTANGLE
] && !gl_info
->supported
[WINED3D_GL_NORMALIZED_TEXRECT
])
1984 const struct wined3d_format
*format
= wined3d_get_format(gl_info
, desc
->format
, desc
->usage
);
1986 /* TODO: Add support for non-power-of-two compressed textures. */
1987 if (format
->flags
[WINED3D_GL_RES_TYPE_TEX_2D
]
1988 & (WINED3DFMT_FLAG_COMPRESSED
| WINED3DFMT_FLAG_HEIGHT_SCALE
))
1990 FIXME("Compressed or height scaled non-power-of-two (%ux%u) textures are not supported.\n",
1991 desc
->width
, desc
->height
);
1992 return WINED3DERR_NOTAVAILABLE
;
1995 /* Find the nearest pow2 match. */
1996 pow2_width
= pow2_height
= 1;
1997 while (pow2_width
< desc
->width
)
1999 while (pow2_height
< desc
->height
)
2001 texture
->flags
|= WINED3D_TEXTURE_COND_NP2_EMULATED
;
2004 texture
->pow2_width
= pow2_width
;
2005 texture
->pow2_height
= pow2_height
;
2007 if ((pow2_width
> gl_info
->limits
.texture_size
|| pow2_height
> gl_info
->limits
.texture_size
)
2008 && (desc
->usage
& WINED3DUSAGE_TEXTURE
))
2010 /* One of four options:
2011 * 1: Do the same as we do with NPOT and scale the texture. (Any
2012 * texture ops would require the texture to be scaled which is
2013 * potentially slow.)
2014 * 2: Set the texture to the maximum size (bad idea).
2015 * 3: WARN and return WINED3DERR_NOTAVAILABLE.
2016 * 4: Create the surface, but allow it to be used only for DirectDraw
2017 * Blts. Some apps (e.g. Swat 3) create textures with a height of
2018 * 16 and a width > 3000 and blt 16x16 letter areas from them to
2019 * the render target. */
2020 if (desc
->pool
== WINED3D_POOL_DEFAULT
|| desc
->pool
== WINED3D_POOL_MANAGED
)
2022 WARN("Dimensions (%ux%u) exceed the maximum texture size.\n", pow2_width
, pow2_height
);
2023 return WINED3DERR_NOTAVAILABLE
;
2026 /* We should never use this surface in combination with OpenGL. */
2027 TRACE("Creating an oversized (%ux%u) surface.\n", pow2_width
, pow2_height
);
2030 /* Calculate levels for mip mapping. */
2031 if (desc
->usage
& WINED3DUSAGE_AUTOGENMIPMAP
)
2033 if (!gl_info
->supported
[SGIS_GENERATE_MIPMAP
])
2035 WARN("No mipmap generation support, returning WINED3DERR_INVALIDCALL.\n");
2036 return WINED3DERR_INVALIDCALL
;
2039 if (level_count
!= 1)
2041 WARN("WINED3DUSAGE_AUTOGENMIPMAP is set, and level count != 1, returning WINED3DERR_INVALIDCALL.\n");
2042 return WINED3DERR_INVALIDCALL
;
2046 if (FAILED(hr
= wined3d_texture_init(texture
, &texture2d_ops
, layer_count
, level_count
, desc
,
2047 flags
, device
, parent
, parent_ops
, &texture_resource_ops
)))
2049 WARN("Failed to initialize texture, returning %#x.\n", hr
);
2053 /* Precalculated scaling for 'faked' non power of two texture coords. */
2054 if (texture
->resource
.gl_type
== WINED3D_GL_RES_TYPE_TEX_RECT
)
2056 texture
->pow2_matrix
[0] = (float)desc
->width
;
2057 texture
->pow2_matrix
[5] = (float)desc
->height
;
2058 texture
->flags
&= ~(WINED3D_TEXTURE_POW2_MAT_IDENT
| WINED3D_TEXTURE_NORMALIZED_COORDS
);
2059 texture
->target
= GL_TEXTURE_RECTANGLE_ARB
;
2063 if (texture
->flags
& WINED3D_TEXTURE_COND_NP2_EMULATED
)
2065 texture
->pow2_matrix
[0] = (((float)desc
->width
) / ((float)pow2_width
));
2066 texture
->pow2_matrix
[5] = (((float)desc
->height
) / ((float)pow2_height
));
2067 texture
->flags
&= ~WINED3D_TEXTURE_POW2_MAT_IDENT
;
2071 texture
->pow2_matrix
[0] = 1.0f
;
2072 texture
->pow2_matrix
[5] = 1.0f
;
2074 if (desc
->usage
& WINED3DUSAGE_LEGACY_CUBEMAP
)
2075 texture
->target
= GL_TEXTURE_CUBE_MAP_ARB
;
2076 else if (layer_count
> 1)
2077 texture
->target
= GL_TEXTURE_2D_ARRAY
;
2079 texture
->target
= GL_TEXTURE_2D
;
2081 texture
->pow2_matrix
[10] = 1.0f
;
2082 texture
->pow2_matrix
[15] = 1.0f
;
2083 TRACE("x scale %.8e, y scale %.8e.\n", texture
->pow2_matrix
[0], texture
->pow2_matrix
[5]);
2085 if (wined3d_texture_use_pbo(texture
, gl_info
))
2086 texture
->resource
.map_binding
= WINED3D_LOCATION_BUFFER
;
2088 if (level_count
> ~(SIZE_T
)0 / layer_count
2089 || !(surfaces
= wined3d_calloc(level_count
* layer_count
, sizeof(*surfaces
))))
2091 wined3d_texture_cleanup_sync(texture
);
2092 return E_OUTOFMEMORY
;
2095 /* Generate all the surfaces. */
2096 for (i
= 0; i
< texture
->level_count
; ++i
)
2098 for (j
= 0; j
< texture
->layer_count
; ++j
)
2100 static const GLenum cube_targets
[6] =
2102 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB
,
2103 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB
,
2104 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB
,
2105 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB
,
2106 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB
,
2107 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
,
2109 struct wined3d_texture_sub_resource
*sub_resource
;
2110 unsigned int idx
= j
* texture
->level_count
+ i
;
2111 struct wined3d_surface
*surface
;
2113 surface
= &surfaces
[idx
];
2114 surface
->container
= texture
;
2115 surface
->texture_target
= desc
->usage
& WINED3DUSAGE_LEGACY_CUBEMAP
? cube_targets
[j
] : texture
->target
;
2116 surface
->texture_level
= i
;
2117 surface
->texture_layer
= j
;
2118 list_init(&surface
->renderbuffers
);
2119 list_init(&surface
->overlays
);
2121 sub_resource
= &texture
->sub_resources
[idx
];
2122 sub_resource
->locations
= WINED3D_LOCATION_DISCARDED
;
2123 sub_resource
->u
.surface
= surface
;
2124 if (!(texture
->resource
.usage
& WINED3DUSAGE_DEPTHSTENCIL
))
2126 wined3d_texture_validate_location(texture
, idx
, WINED3D_LOCATION_SYSMEM
);
2127 wined3d_texture_invalidate_location(texture
, idx
, ~WINED3D_LOCATION_SYSMEM
);
2130 if (FAILED(hr
= device_parent
->ops
->surface_created(device_parent
,
2131 texture
, idx
, &sub_resource
->parent
, &sub_resource
->parent_ops
)))
2133 WARN("Failed to create surface parent, hr %#x.\n", hr
);
2134 sub_resource
->parent
= NULL
;
2135 wined3d_texture_cleanup_sync(texture
);
2139 TRACE("parent %p, parent_ops %p.\n", sub_resource
->parent
, sub_resource
->parent_ops
);
2141 TRACE("Created surface level %u, layer %u @ %p.\n", i
, j
, surface
);
2143 if (((desc
->usage
& WINED3DUSAGE_OWNDC
) || (device
->wined3d
->flags
& WINED3D_NO3D
))
2144 && FAILED(hr
= wined3d_surface_create_dc(surface
)))
2146 wined3d_texture_cleanup_sync(texture
);
2155 /* This call just uploads data, the caller is responsible for binding the
2156 * correct texture. */
2157 /* Context activation is done by the caller. */
2158 static void texture3d_upload_data(struct wined3d_texture
*texture
, unsigned int sub_resource_idx
,
2159 const struct wined3d_context
*context
, const struct wined3d_box
*box
,
2160 const struct wined3d_const_bo_address
*data
, unsigned int row_pitch
, unsigned int slice_pitch
)
2162 const struct wined3d_format
*format
= texture
->resource
.format
;
2163 unsigned int level
= sub_resource_idx
% texture
->level_count
;
2164 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
2165 unsigned int x
, y
, z
, update_w
, update_h
, update_d
;
2166 unsigned int dst_row_pitch
, dst_slice_pitch
;
2167 unsigned int width
, height
, depth
;
2168 const void *mem
= data
->addr
;
2169 void *converted_mem
= NULL
;
2171 TRACE("texture %p, sub_resource_idx %u, context %p, box %s, data {%#x:%p}, row_pitch %#x, slice_pitch %#x.\n",
2172 texture
, sub_resource_idx
, context
, debug_box(box
),
2173 data
->buffer_object
, data
->addr
, row_pitch
, slice_pitch
);
2175 width
= wined3d_texture_get_level_width(texture
, level
);
2176 height
= wined3d_texture_get_level_height(texture
, level
);
2177 depth
= wined3d_texture_get_level_depth(texture
, level
);
2191 update_w
= box
->right
- box
->left
;
2192 update_h
= box
->bottom
- box
->top
;
2193 update_d
= box
->back
- box
->front
;
2196 if (format
->convert
)
2198 if (data
->buffer_object
)
2199 ERR("Loading a converted texture from a PBO.\n");
2200 if (texture
->resource
.format_flags
& WINED3DFMT_FLAG_BLOCKS
)
2201 ERR("Converting a block-based format.\n");
2203 dst_row_pitch
= update_w
* format
->conv_byte_count
;
2204 dst_slice_pitch
= dst_row_pitch
* update_h
;
2206 converted_mem
= wined3d_calloc(update_d
, dst_slice_pitch
);
2207 format
->convert(data
->addr
, converted_mem
, row_pitch
, slice_pitch
,
2208 dst_row_pitch
, dst_slice_pitch
, update_w
, update_h
, update_d
);
2209 mem
= converted_mem
;
2213 wined3d_texture_get_pitch(texture
, sub_resource_idx
, &dst_row_pitch
, &dst_slice_pitch
);
2214 if (row_pitch
!= dst_row_pitch
|| slice_pitch
!= dst_slice_pitch
)
2215 FIXME("Ignoring row/slice pitch (%u/%u).\n", row_pitch
, slice_pitch
);
2218 if (data
->buffer_object
)
2220 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, data
->buffer_object
));
2221 checkGLcall("glBindBuffer");
2224 GL_EXTCALL(glTexSubImage3D(GL_TEXTURE_3D
, level
, x
, y
, z
,
2225 update_w
, update_h
, update_d
, format
->glFormat
, format
->glType
, mem
));
2226 checkGLcall("glTexSubImage3D");
2228 if (data
->buffer_object
)
2230 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, 0));
2231 checkGLcall("glBindBuffer");
2234 HeapFree(GetProcessHeap(), 0, converted_mem
);
2237 /* Context activation is done by the caller. */
2238 static void texture3d_download_data(struct wined3d_texture
*texture
, unsigned int sub_resource_idx
,
2239 const struct wined3d_context
*context
, const struct wined3d_bo_address
*data
)
2241 const struct wined3d_format
*format
= texture
->resource
.format
;
2242 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
2244 if (format
->convert
)
2246 FIXME("Attempting to download a converted volume, format %s.\n",
2247 debug_d3dformat(format
->id
));
2251 if (data
->buffer_object
)
2253 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, data
->buffer_object
));
2254 checkGLcall("glBindBuffer");
2257 gl_info
->gl_ops
.gl
.p_glGetTexImage(GL_TEXTURE_3D
, sub_resource_idx
,
2258 format
->glFormat
, format
->glType
, data
->addr
);
2259 checkGLcall("glGetTexImage");
2261 if (data
->buffer_object
)
2263 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, 0));
2264 checkGLcall("glBindBuffer");
2269 /* Context activation is done by the caller. */
2270 static void texture3d_srgb_transfer(struct wined3d_texture
*texture
, unsigned int sub_resource_idx
,
2271 struct wined3d_context
*context
, BOOL dest_is_srgb
)
2273 struct wined3d_texture_sub_resource
*sub_resource
= &texture
->sub_resources
[sub_resource_idx
];
2274 unsigned int row_pitch
, slice_pitch
;
2275 struct wined3d_bo_address data
;
2277 /* Optimisations are possible, but the effort should be put into either
2278 * implementing EXT_SRGB_DECODE in the driver or finding out why we
2279 * picked the wrong copy for the original upload and fixing that.
2281 * Also keep in mind that we want to avoid using resource.heap_memory
2282 * for DEFAULT pool surfaces. */
2283 WARN_(d3d_perf
)("Performing slow rgb/srgb volume transfer.\n");
2284 data
.buffer_object
= 0;
2285 if (!(data
.addr
= HeapAlloc(GetProcessHeap(), 0, sub_resource
->size
)))
2288 wined3d_texture_get_pitch(texture
, sub_resource_idx
, &row_pitch
, &slice_pitch
);
2289 wined3d_texture_bind_and_dirtify(texture
, context
, !dest_is_srgb
);
2290 texture3d_download_data(texture
, sub_resource_idx
, context
, &data
);
2291 wined3d_texture_bind_and_dirtify(texture
, context
, dest_is_srgb
);
2292 texture3d_upload_data(texture
, sub_resource_idx
, context
,
2293 NULL
, wined3d_const_bo_address(&data
), row_pitch
, slice_pitch
);
2295 HeapFree(GetProcessHeap(), 0, data
.addr
);
2298 /* Context activation is done by the caller. */
2299 static BOOL
texture3d_load_location(struct wined3d_texture
*texture
, unsigned int sub_resource_idx
,
2300 struct wined3d_context
*context
, DWORD location
)
2302 struct wined3d_texture_sub_resource
*sub_resource
= &texture
->sub_resources
[sub_resource_idx
];
2303 unsigned int row_pitch
, slice_pitch
;
2305 if (!wined3d_texture_prepare_location(texture
, sub_resource_idx
, context
, location
))
2310 case WINED3D_LOCATION_TEXTURE_RGB
:
2311 case WINED3D_LOCATION_TEXTURE_SRGB
:
2312 if (sub_resource
->locations
& WINED3D_LOCATION_SYSMEM
)
2314 struct wined3d_const_bo_address data
= {0, texture
->resource
.heap_memory
};
2315 data
.addr
+= sub_resource
->offset
;
2316 wined3d_texture_bind_and_dirtify(texture
, context
,
2317 location
== WINED3D_LOCATION_TEXTURE_SRGB
);
2318 wined3d_texture_get_pitch(texture
, sub_resource_idx
, &row_pitch
, &slice_pitch
);
2319 texture3d_upload_data(texture
, sub_resource_idx
, context
, NULL
, &data
, row_pitch
, slice_pitch
);
2321 else if (sub_resource
->locations
& WINED3D_LOCATION_BUFFER
)
2323 struct wined3d_const_bo_address data
= {sub_resource
->buffer_object
, NULL
};
2324 wined3d_texture_bind_and_dirtify(texture
, context
,
2325 location
== WINED3D_LOCATION_TEXTURE_SRGB
);
2326 wined3d_texture_get_pitch(texture
, sub_resource_idx
, &row_pitch
, &slice_pitch
);
2327 texture3d_upload_data(texture
, sub_resource_idx
, context
, NULL
, &data
, row_pitch
, slice_pitch
);
2329 else if (sub_resource
->locations
& WINED3D_LOCATION_TEXTURE_RGB
)
2331 texture3d_srgb_transfer(texture
, sub_resource_idx
, context
, TRUE
);
2333 else if (sub_resource
->locations
& WINED3D_LOCATION_TEXTURE_SRGB
)
2335 texture3d_srgb_transfer(texture
, sub_resource_idx
, context
, FALSE
);
2339 FIXME("Implement texture loading from %s.\n", wined3d_debug_location(sub_resource
->locations
));
2344 case WINED3D_LOCATION_SYSMEM
:
2345 if (sub_resource
->locations
& (WINED3D_LOCATION_TEXTURE_RGB
| WINED3D_LOCATION_TEXTURE_SRGB
))
2347 struct wined3d_bo_address data
= {0, texture
->resource
.heap_memory
};
2349 data
.addr
+= sub_resource
->offset
;
2350 if (sub_resource
->locations
& WINED3D_LOCATION_TEXTURE_RGB
)
2351 wined3d_texture_bind_and_dirtify(texture
, context
, FALSE
);
2353 wined3d_texture_bind_and_dirtify(texture
, context
, TRUE
);
2355 texture3d_download_data(texture
, sub_resource_idx
, context
, &data
);
2356 ++texture
->download_count
;
2360 FIXME("Implement WINED3D_LOCATION_SYSMEM loading from %s.\n",
2361 wined3d_debug_location(sub_resource
->locations
));
2366 case WINED3D_LOCATION_BUFFER
:
2367 if (sub_resource
->locations
& (WINED3D_LOCATION_TEXTURE_RGB
| WINED3D_LOCATION_TEXTURE_SRGB
))
2369 struct wined3d_bo_address data
= {sub_resource
->buffer_object
, NULL
};
2371 if (sub_resource
->locations
& WINED3D_LOCATION_TEXTURE_RGB
)
2372 wined3d_texture_bind_and_dirtify(texture
, context
, FALSE
);
2374 wined3d_texture_bind_and_dirtify(texture
, context
, TRUE
);
2376 texture3d_download_data(texture
, sub_resource_idx
, context
, &data
);
2380 FIXME("Implement WINED3D_LOCATION_BUFFER loading from %s.\n",
2381 wined3d_debug_location(sub_resource
->locations
));
2387 FIXME("Implement %s loading from %s.\n", wined3d_debug_location(location
),
2388 wined3d_debug_location(sub_resource
->locations
));
2395 static void texture3d_prepare_texture(struct wined3d_texture
*texture
, struct wined3d_context
*context
, BOOL srgb
)
2397 const struct wined3d_format
*format
= texture
->resource
.format
;
2398 GLenum internal
= srgb
? format
->glGammaInternal
: format
->glInternal
;
2399 unsigned int sub_count
= texture
->level_count
* texture
->layer_count
;
2400 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
2403 wined3d_texture_bind_and_dirtify(texture
, context
, srgb
);
2405 if (wined3d_texture_use_immutable_storage(texture
, gl_info
))
2407 GL_EXTCALL(glTexStorage3D(GL_TEXTURE_3D
, texture
->level_count
, internal
,
2408 wined3d_texture_get_level_width(texture
, 0),
2409 wined3d_texture_get_level_height(texture
, 0),
2410 wined3d_texture_get_level_depth(texture
, 0)));
2411 checkGLcall("glTexStorage3D");
2415 for (i
= 0; i
< sub_count
; ++i
)
2417 GL_EXTCALL(glTexImage3D(GL_TEXTURE_3D
, i
, internal
,
2418 wined3d_texture_get_level_width(texture
, i
),
2419 wined3d_texture_get_level_height(texture
, i
),
2420 wined3d_texture_get_level_depth(texture
, i
),
2421 0, format
->glFormat
, format
->glType
, NULL
));
2422 checkGLcall("glTexImage3D");
2427 static void texture3d_cleanup_sub_resources(struct wined3d_texture
*texture
)
2431 static const struct wined3d_texture_ops texture3d_ops
=
2433 texture3d_upload_data
,
2434 texture3d_load_location
,
2435 texture3d_prepare_texture
,
2436 texture3d_cleanup_sub_resources
,
2439 BOOL
wined3d_texture_check_block_align(const struct wined3d_texture
*texture
,
2440 unsigned int level
, const struct wined3d_box
*box
)
2442 const struct wined3d_format
*format
= texture
->resource
.format
;
2443 unsigned int height
= wined3d_texture_get_level_height(texture
, level
);
2444 unsigned int width
= wined3d_texture_get_level_width(texture
, level
);
2445 unsigned int width_mask
, height_mask
;
2447 if ((box
->left
>= box
->right
)
2448 || (box
->top
>= box
->bottom
)
2449 || (box
->right
> width
)
2450 || (box
->bottom
> height
))
2453 /* This assumes power of two block sizes, but NPOT block sizes would be
2456 * This also assumes that the format's block depth is 1. */
2457 width_mask
= format
->block_width
- 1;
2458 height_mask
= format
->block_height
- 1;
2460 if ((box
->left
& width_mask
) || (box
->top
& height_mask
)
2461 || (box
->right
& width_mask
&& box
->right
!= width
)
2462 || (box
->bottom
& height_mask
&& box
->bottom
!= height
))
2468 static HRESULT
volumetexture_init(struct wined3d_texture
*texture
, const struct wined3d_resource_desc
*desc
,
2469 UINT layer_count
, UINT level_count
, struct wined3d_device
*device
, void *parent
,
2470 const struct wined3d_parent_ops
*parent_ops
)
2472 struct wined3d_device_parent
*device_parent
= device
->device_parent
;
2473 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
2477 if (layer_count
!= 1)
2479 ERR("Invalid layer count for volume texture.\n");
2480 return E_INVALIDARG
;
2483 /* TODO: It should only be possible to create textures for formats
2484 * that are reported as supported. */
2485 if (WINED3DFMT_UNKNOWN
>= desc
->format
)
2487 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN.\n", texture
);
2488 return WINED3DERR_INVALIDCALL
;
2491 if (!gl_info
->supported
[EXT_TEXTURE3D
])
2493 WARN("(%p) : Texture cannot be created - no volume texture support.\n", texture
);
2494 return WINED3DERR_INVALIDCALL
;
2497 /* Calculate levels for mip mapping. */
2498 if (desc
->usage
& WINED3DUSAGE_AUTOGENMIPMAP
)
2500 if (!gl_info
->supported
[SGIS_GENERATE_MIPMAP
])
2502 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL.\n");
2503 return WINED3DERR_INVALIDCALL
;
2506 if (level_count
!= 1)
2508 WARN("WINED3DUSAGE_AUTOGENMIPMAP is set, and level count != 1, returning D3DERR_INVALIDCALL.\n");
2509 return WINED3DERR_INVALIDCALL
;
2513 if (desc
->usage
& WINED3DUSAGE_DYNAMIC
&& (desc
->pool
== WINED3D_POOL_MANAGED
2514 || desc
->pool
== WINED3D_POOL_SCRATCH
))
2516 WARN("Attempted to create a DYNAMIC texture in pool %s.\n", debug_d3dpool(desc
->pool
));
2517 return WINED3DERR_INVALIDCALL
;
2520 if (!gl_info
->supported
[ARB_TEXTURE_NON_POWER_OF_TWO
])
2522 UINT pow2_w
, pow2_h
, pow2_d
;
2524 while (pow2_w
< desc
->width
)
2527 while (pow2_h
< desc
->height
)
2530 while (pow2_d
< desc
->depth
)
2533 if (pow2_w
!= desc
->width
|| pow2_h
!= desc
->height
|| pow2_d
!= desc
->depth
)
2535 if (desc
->pool
== WINED3D_POOL_SCRATCH
)
2537 WARN("Creating a scratch NPOT volume texture despite lack of HW support.\n");
2541 WARN("Attempted to create a NPOT volume texture (%u, %u, %u) without GL support.\n",
2542 desc
->width
, desc
->height
, desc
->depth
);
2543 return WINED3DERR_INVALIDCALL
;
2548 if (FAILED(hr
= wined3d_texture_init(texture
, &texture3d_ops
, 1, level_count
, desc
,
2549 0, device
, parent
, parent_ops
, &texture_resource_ops
)))
2551 WARN("Failed to initialize texture, returning %#x.\n", hr
);
2555 texture
->pow2_matrix
[0] = 1.0f
;
2556 texture
->pow2_matrix
[5] = 1.0f
;
2557 texture
->pow2_matrix
[10] = 1.0f
;
2558 texture
->pow2_matrix
[15] = 1.0f
;
2559 texture
->target
= GL_TEXTURE_3D
;
2561 if (wined3d_texture_use_pbo(texture
, gl_info
))
2563 wined3d_resource_free_sysmem(&texture
->resource
);
2564 texture
->resource
.map_binding
= WINED3D_LOCATION_BUFFER
;
2567 /* Generate all the surfaces. */
2568 for (i
= 0; i
< texture
->level_count
; ++i
)
2570 struct wined3d_texture_sub_resource
*sub_resource
;
2572 sub_resource
= &texture
->sub_resources
[i
];
2573 sub_resource
->locations
= WINED3D_LOCATION_DISCARDED
;
2575 if (FAILED(hr
= device_parent
->ops
->volume_created(device_parent
,
2576 texture
, i
, &sub_resource
->parent
, &sub_resource
->parent_ops
)))
2578 WARN("Failed to create volume parent, hr %#x.\n", hr
);
2579 sub_resource
->parent
= NULL
;
2580 wined3d_texture_cleanup_sync(texture
);
2584 TRACE("parent %p, parent_ops %p.\n", parent
, parent_ops
);
2586 TRACE("Created volume level %u.\n", i
);
2592 HRESULT CDECL
wined3d_texture_blt(struct wined3d_texture
*dst_texture
, unsigned int dst_sub_resource_idx
,
2593 const RECT
*dst_rect
, struct wined3d_texture
*src_texture
, unsigned int src_sub_resource_idx
,
2594 const RECT
*src_rect
, DWORD flags
, const struct wined3d_blt_fx
*fx
, enum wined3d_texture_filter_type filter
)
2596 struct wined3d_texture_sub_resource
*dst_resource
, *src_resource
= NULL
;
2598 TRACE("dst_texture %p, dst_sub_resource_idx %u, dst_rect %s, src_texture %p, "
2599 "src_sub_resource_idx %u, src_rect %s, flags %#x, fx %p, filter %s.\n",
2600 dst_texture
, dst_sub_resource_idx
, wine_dbgstr_rect(dst_rect
), src_texture
,
2601 src_sub_resource_idx
, wine_dbgstr_rect(src_rect
), flags
, fx
, debug_d3dtexturefiltertype(filter
));
2603 if (!(dst_resource
= wined3d_texture_get_sub_resource(dst_texture
, dst_sub_resource_idx
))
2604 || dst_texture
->resource
.type
!= WINED3D_RTYPE_TEXTURE_2D
)
2605 return WINED3DERR_INVALIDCALL
;
2609 if (!(src_resource
= wined3d_texture_get_sub_resource(src_texture
, src_sub_resource_idx
))
2610 || src_texture
->resource
.type
!= WINED3D_RTYPE_TEXTURE_2D
)
2611 return WINED3DERR_INVALIDCALL
;
2614 return wined3d_surface_blt(dst_resource
->u
.surface
, dst_rect
,
2615 src_resource
? src_resource
->u
.surface
: NULL
, src_rect
, flags
, fx
, filter
);
2618 HRESULT CDECL
wined3d_texture_get_overlay_position(const struct wined3d_texture
*texture
,
2619 unsigned int sub_resource_idx
, LONG
*x
, LONG
*y
)
2621 struct wined3d_surface
*surface
;
2623 TRACE("texture %p, sub_resource_idx %u, x %p, y %p.\n", texture
, sub_resource_idx
, x
, y
);
2625 if (!(texture
->resource
.usage
& WINED3DUSAGE_OVERLAY
) || texture
->resource
.type
!= WINED3D_RTYPE_TEXTURE_2D
2626 || sub_resource_idx
>= texture
->level_count
* texture
->layer_count
)
2628 WARN("Invalid sub-resource specified.\n");
2629 return WINEDDERR_NOTAOVERLAYSURFACE
;
2632 surface
= texture
->sub_resources
[sub_resource_idx
].u
.surface
;
2633 if (!surface
->overlay_dest
)
2635 TRACE("Overlay not visible.\n");
2638 return WINEDDERR_OVERLAYNOTVISIBLE
;
2641 *x
= surface
->overlay_destrect
.left
;
2642 *y
= surface
->overlay_destrect
.top
;
2644 TRACE("Returning position %d, %d.\n", *x
, *y
);
2649 HRESULT CDECL
wined3d_texture_set_overlay_position(struct wined3d_texture
*texture
,
2650 unsigned int sub_resource_idx
, LONG x
, LONG y
)
2652 struct wined3d_texture_sub_resource
*sub_resource
;
2653 struct wined3d_surface
*surface
;
2656 TRACE("texture %p, sub_resource_idx %u, x %d, y %d.\n", texture
, sub_resource_idx
, x
, y
);
2658 if (!(texture
->resource
.usage
& WINED3DUSAGE_OVERLAY
) || texture
->resource
.type
!= WINED3D_RTYPE_TEXTURE_2D
2659 || !(sub_resource
= wined3d_texture_get_sub_resource(texture
, sub_resource_idx
)))
2661 WARN("Invalid sub-resource specified.\n");
2662 return WINEDDERR_NOTAOVERLAYSURFACE
;
2665 surface
= sub_resource
->u
.surface
;
2666 w
= surface
->overlay_destrect
.right
- surface
->overlay_destrect
.left
;
2667 h
= surface
->overlay_destrect
.bottom
- surface
->overlay_destrect
.top
;
2668 SetRect(&surface
->overlay_destrect
, x
, y
, x
+ w
, y
+ h
);
2673 HRESULT CDECL
wined3d_texture_update_overlay(struct wined3d_texture
*texture
, unsigned int sub_resource_idx
,
2674 const RECT
*src_rect
, struct wined3d_texture
*dst_texture
, unsigned int dst_sub_resource_idx
,
2675 const RECT
*dst_rect
, DWORD flags
)
2677 struct wined3d_texture_sub_resource
*sub_resource
, *dst_sub_resource
;
2678 struct wined3d_surface
*surface
, *dst_surface
;
2680 TRACE("texture %p, sub_resource_idx %u, src_rect %s, dst_texture %p, "
2681 "dst_sub_resource_idx %u, dst_rect %s, flags %#x.\n",
2682 texture
, sub_resource_idx
, wine_dbgstr_rect(src_rect
), dst_texture
,
2683 dst_sub_resource_idx
, wine_dbgstr_rect(dst_rect
), flags
);
2685 if (!(texture
->resource
.usage
& WINED3DUSAGE_OVERLAY
) || texture
->resource
.type
!= WINED3D_RTYPE_TEXTURE_2D
2686 || !(sub_resource
= wined3d_texture_get_sub_resource(texture
, sub_resource_idx
)))
2688 WARN("Invalid sub-resource specified.\n");
2689 return WINEDDERR_NOTAOVERLAYSURFACE
;
2692 if (!dst_texture
|| dst_texture
->resource
.type
!= WINED3D_RTYPE_TEXTURE_2D
2693 || !(dst_sub_resource
= wined3d_texture_get_sub_resource(dst_texture
, dst_sub_resource_idx
)))
2695 WARN("Invalid destination sub-resource specified.\n");
2696 return WINED3DERR_INVALIDCALL
;
2699 surface
= sub_resource
->u
.surface
;
2701 surface
->overlay_srcrect
= *src_rect
;
2703 SetRect(&surface
->overlay_srcrect
, 0, 0,
2704 wined3d_texture_get_level_width(texture
, surface
->texture_level
),
2705 wined3d_texture_get_level_height(texture
, surface
->texture_level
));
2707 dst_surface
= dst_sub_resource
->u
.surface
;
2709 surface
->overlay_destrect
= *dst_rect
;
2711 SetRect(&surface
->overlay_destrect
, 0, 0,
2712 wined3d_texture_get_level_width(dst_texture
, dst_surface
->texture_level
),
2713 wined3d_texture_get_level_height(dst_texture
, dst_surface
->texture_level
));
2715 if (surface
->overlay_dest
&& (surface
->overlay_dest
!= dst_surface
|| flags
& WINEDDOVER_HIDE
))
2717 surface
->overlay_dest
= NULL
;
2718 list_remove(&surface
->overlay_entry
);
2721 if (flags
& WINEDDOVER_SHOW
)
2723 if (surface
->overlay_dest
!= dst_surface
)
2725 surface
->overlay_dest
= dst_surface
;
2726 list_add_tail(&dst_surface
->overlays
, &surface
->overlay_entry
);
2729 else if (flags
& WINEDDOVER_HIDE
)
2731 /* Tests show that the rectangles are erased on hide. */
2732 SetRectEmpty(&surface
->overlay_srcrect
);
2733 SetRectEmpty(&surface
->overlay_destrect
);
2734 surface
->overlay_dest
= NULL
;
2740 void * CDECL
wined3d_texture_get_sub_resource_parent(struct wined3d_texture
*texture
, unsigned int sub_resource_idx
)
2742 unsigned int sub_count
= texture
->level_count
* texture
->layer_count
;
2744 TRACE("texture %p, sub_resource_idx %u.\n", texture
, sub_resource_idx
);
2746 if (sub_resource_idx
>= sub_count
)
2748 WARN("sub_resource_idx %u >= sub_count %u.\n", sub_resource_idx
, sub_count
);
2752 return texture
->sub_resources
[sub_resource_idx
].parent
;
2755 void CDECL
wined3d_texture_set_sub_resource_parent(struct wined3d_texture
*texture
,
2756 unsigned int sub_resource_idx
, void *parent
)
2758 unsigned int sub_count
= texture
->level_count
* texture
->layer_count
;
2760 TRACE("texture %p, sub_resource_idx %u, parent %p.\n", texture
, sub_resource_idx
, parent
);
2762 if (sub_resource_idx
>= sub_count
)
2764 WARN("sub_resource_idx %u >= sub_count %u.\n", sub_resource_idx
, sub_count
);
2768 texture
->sub_resources
[sub_resource_idx
].parent
= parent
;
2771 HRESULT CDECL
wined3d_texture_get_sub_resource_desc(const struct wined3d_texture
*texture
,
2772 unsigned int sub_resource_idx
, struct wined3d_sub_resource_desc
*desc
)
2774 unsigned int sub_count
= texture
->level_count
* texture
->layer_count
;
2775 const struct wined3d_resource
*resource
;
2776 unsigned int level_idx
;
2778 TRACE("texture %p, sub_resource_idx %u, desc %p.\n", texture
, sub_resource_idx
, desc
);
2780 if (sub_resource_idx
>= sub_count
)
2782 WARN("sub_resource_idx %u >= sub_count %u.\n", sub_resource_idx
, sub_count
);
2783 return WINED3DERR_INVALIDCALL
;
2786 resource
= &texture
->resource
;
2787 desc
->format
= resource
->format
->id
;
2788 desc
->multisample_type
= resource
->multisample_type
;
2789 desc
->multisample_quality
= resource
->multisample_quality
;
2790 desc
->usage
= resource
->usage
;
2791 desc
->pool
= resource
->pool
;
2793 level_idx
= sub_resource_idx
% texture
->level_count
;
2794 desc
->width
= wined3d_texture_get_level_width(texture
, level_idx
);
2795 desc
->height
= wined3d_texture_get_level_height(texture
, level_idx
);
2796 desc
->depth
= wined3d_texture_get_level_depth(texture
, level_idx
);
2797 desc
->size
= texture
->sub_resources
[sub_resource_idx
].size
;
2802 HRESULT CDECL
wined3d_texture_create(struct wined3d_device
*device
, const struct wined3d_resource_desc
*desc
,
2803 UINT layer_count
, UINT level_count
, DWORD flags
, const struct wined3d_sub_resource_data
*data
,
2804 void *parent
, const struct wined3d_parent_ops
*parent_ops
, struct wined3d_texture
**texture
)
2806 struct wined3d_texture
*object
;
2809 TRACE("device %p, desc %p, layer_count %u, level_count %u, flags %#x, data %p, "
2810 "parent %p, parent_ops %p, texture %p.\n",
2811 device
, desc
, layer_count
, level_count
, flags
, data
, parent
, parent_ops
, texture
);
2815 WARN("Invalid layer count.\n");
2816 return E_INVALIDARG
;
2818 if ((desc
->usage
& WINED3DUSAGE_LEGACY_CUBEMAP
) && layer_count
!= 6)
2820 ERR("Invalid layer count %u for legacy cubemap.\n", layer_count
);
2826 WARN("Invalid level count.\n");
2827 return WINED3DERR_INVALIDCALL
;
2830 if (desc
->multisample_type
!= WINED3D_MULTISAMPLE_NONE
)
2832 const struct wined3d_format
*format
= wined3d_get_format(&device
->adapter
->gl_info
,
2833 desc
->format
, desc
->usage
);
2835 if (desc
->multisample_type
== WINED3D_MULTISAMPLE_NON_MASKABLE
2836 && desc
->multisample_quality
>= wined3d_popcount(format
->multisample_types
))
2838 WARN("Unsupported quality level %u requested for WINED3D_MULTISAMPLE_NON_MASKABLE.\n",
2839 desc
->multisample_quality
);
2840 return WINED3DERR_NOTAVAILABLE
;
2842 if (desc
->multisample_type
!= WINED3D_MULTISAMPLE_NON_MASKABLE
2843 && (!(format
->multisample_types
& 1u << (desc
->multisample_type
- 1))
2844 || desc
->multisample_quality
))
2846 WARN("Unsupported multisample type %u quality %u requested.\n", desc
->multisample_type
,
2847 desc
->multisample_quality
);
2848 return WINED3DERR_NOTAVAILABLE
;
2852 if (!(object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
2853 FIELD_OFFSET(struct wined3d_texture
, sub_resources
[level_count
* layer_count
]))))
2854 return E_OUTOFMEMORY
;
2856 switch (desc
->resource_type
)
2858 case WINED3D_RTYPE_TEXTURE_2D
:
2859 hr
= texture_init(object
, desc
, layer_count
, level_count
, flags
, device
, parent
, parent_ops
);
2862 case WINED3D_RTYPE_TEXTURE_3D
:
2863 hr
= volumetexture_init(object
, desc
, layer_count
, level_count
, device
, parent
, parent_ops
);
2867 ERR("Invalid resource type %s.\n", debug_d3dresourcetype(desc
->resource_type
));
2868 hr
= WINED3DERR_INVALIDCALL
;
2874 WARN("Failed to initialize texture, returning %#x.\n", hr
);
2875 HeapFree(GetProcessHeap(), 0, object
);
2879 /* FIXME: We'd like to avoid ever allocating system memory for the texture
2883 unsigned int sub_count
= level_count
* layer_count
;
2886 for (i
= 0; i
< sub_count
; ++i
)
2890 WARN("Invalid sub-resource data specified for sub-resource %u.\n", i
);
2891 wined3d_texture_cleanup_sync(object
);
2892 HeapFree(GetProcessHeap(), 0, object
);
2893 return E_INVALIDARG
;
2897 for (i
= 0; i
< sub_count
; ++i
)
2899 wined3d_device_update_sub_resource(device
, &object
->resource
,
2900 i
, NULL
, data
[i
].data
, data
[i
].row_pitch
, data
[i
].slice_pitch
);
2904 TRACE("Created texture %p.\n", object
);
2910 HRESULT CDECL
wined3d_texture_get_dc(struct wined3d_texture
*texture
, unsigned int sub_resource_idx
, HDC
*dc
)
2912 struct wined3d_device
*device
= texture
->resource
.device
;
2913 struct wined3d_texture_sub_resource
*sub_resource
;
2914 struct wined3d_context
*context
= NULL
;
2915 struct wined3d_surface
*surface
;
2916 HRESULT hr
= WINED3D_OK
;
2918 TRACE("texture %p, sub_resource_idx %u, dc %p.\n", texture
, sub_resource_idx
, dc
);
2920 if (!(texture
->flags
& WINED3D_TEXTURE_GET_DC
))
2922 WARN("Texture does not support GetDC\n");
2923 /* Don't touch the DC */
2924 return WINED3DERR_INVALIDCALL
;
2927 if (!(sub_resource
= wined3d_texture_get_sub_resource(texture
, sub_resource_idx
)))
2928 return WINED3DERR_INVALIDCALL
;
2930 if (texture
->resource
.type
!= WINED3D_RTYPE_TEXTURE_2D
)
2932 WARN("Not supported on %s resources.\n", debug_d3dresourcetype(texture
->resource
.type
));
2933 return WINED3DERR_INVALIDCALL
;
2936 surface
= sub_resource
->u
.surface
;
2938 if (texture
->resource
.map_count
&& !(texture
->flags
& WINED3D_TEXTURE_GET_DC_LENIENT
))
2939 return WINED3DERR_INVALIDCALL
;
2941 if (device
->d3d_initialized
)
2942 context
= context_acquire(device
, NULL
);
2944 wined3d_texture_load_location(texture
, sub_resource_idx
, context
, texture
->resource
.map_binding
);
2945 wined3d_texture_invalidate_location(texture
, sub_resource_idx
, ~texture
->resource
.map_binding
);
2948 hr
= wined3d_surface_create_dc(surface
);
2950 context_release(context
);
2952 return WINED3DERR_INVALIDCALL
;
2954 if (!(texture
->flags
& WINED3D_TEXTURE_GET_DC_LENIENT
))
2955 texture
->flags
|= WINED3D_TEXTURE_DC_IN_USE
;
2956 ++texture
->resource
.map_count
;
2957 ++sub_resource
->map_count
;
2960 TRACE("Returning dc %p.\n", *dc
);
2965 HRESULT CDECL
wined3d_texture_release_dc(struct wined3d_texture
*texture
, unsigned int sub_resource_idx
, HDC dc
)
2967 struct wined3d_device
*device
= texture
->resource
.device
;
2968 struct wined3d_texture_sub_resource
*sub_resource
;
2969 struct wined3d_surface
*surface
;
2971 TRACE("texture %p, sub_resource_idx %u, dc %p.\n", texture
, sub_resource_idx
, dc
);
2973 if (!(sub_resource
= wined3d_texture_get_sub_resource(texture
, sub_resource_idx
)))
2974 return WINED3DERR_INVALIDCALL
;
2976 if (texture
->resource
.type
!= WINED3D_RTYPE_TEXTURE_2D
)
2978 WARN("Not supported on %s resources.\n", debug_d3dresourcetype(texture
->resource
.type
));
2979 return WINED3DERR_INVALIDCALL
;
2982 surface
= sub_resource
->u
.surface
;
2984 if (!(texture
->flags
& (WINED3D_TEXTURE_GET_DC_LENIENT
| WINED3D_TEXTURE_DC_IN_USE
)))
2985 return WINED3DERR_INVALIDCALL
;
2987 if (surface
->dc
!= dc
)
2989 WARN("Application tries to release invalid DC %p, surface DC is %p.\n", dc
, surface
->dc
);
2990 return WINED3DERR_INVALIDCALL
;
2993 if (!(texture
->resource
.usage
& WINED3DUSAGE_OWNDC
) && !(device
->wined3d
->flags
& WINED3D_NO3D
))
2994 wined3d_surface_destroy_dc(surface
);
2996 --sub_resource
->map_count
;
2997 if (!--texture
->resource
.map_count
&& texture
->update_map_binding
)
2998 wined3d_texture_update_map_binding(texture
);
2999 if (!(texture
->flags
& WINED3D_TEXTURE_GET_DC_LENIENT
))
3000 texture
->flags
&= ~WINED3D_TEXTURE_DC_IN_USE
;