2 * Copyright 1997-2000 Marcus Meissner
3 * Copyright 1998-2000 Lionel Ulmer
4 * Copyright 2000-2001 TransGaming Technologies Inc.
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2002-2003 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2011, 2013-2014 Stefan Dösinger for CodeWeavers
10 * Copyright 2007-2008 Henri Verbeet
11 * Copyright 2006-2008 Roderick Colenbrander
12 * Copyright 2009-2011 Henri Verbeet for CodeWeavers
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
30 #include "wine/port.h"
31 #include "wined3d_private.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface
);
34 WINE_DECLARE_DEBUG_CHANNEL(d3d_perf
);
35 WINE_DECLARE_DEBUG_CHANNEL(d3d
);
37 #define MAXLOCKCOUNT 50 /* After this amount of locks do not free the sysmem copy. */
39 static const DWORD surface_simple_locations
=
40 WINED3D_LOCATION_SYSMEM
| WINED3D_LOCATION_USER_MEMORY
41 | WINED3D_LOCATION_DIB
| WINED3D_LOCATION_BUFFER
;
43 static void surface_cleanup(struct wined3d_surface
*surface
)
45 struct wined3d_surface
*overlay
, *cur
;
47 TRACE("surface %p.\n", surface
);
49 if (surface
->pbo
|| surface
->rb_multisample
50 || surface
->rb_resolved
|| !list_empty(&surface
->renderbuffers
))
52 struct wined3d_renderbuffer_entry
*entry
, *entry2
;
53 const struct wined3d_gl_info
*gl_info
;
54 struct wined3d_context
*context
;
56 context
= context_acquire(surface
->resource
.device
, NULL
);
57 gl_info
= context
->gl_info
;
61 TRACE("Deleting PBO %u.\n", surface
->pbo
);
62 GL_EXTCALL(glDeleteBuffersARB(1, &surface
->pbo
));
65 if (surface
->rb_multisample
)
67 TRACE("Deleting multisample renderbuffer %u.\n", surface
->rb_multisample
);
68 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &surface
->rb_multisample
);
71 if (surface
->rb_resolved
)
73 TRACE("Deleting resolved renderbuffer %u.\n", surface
->rb_resolved
);
74 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &surface
->rb_resolved
);
77 LIST_FOR_EACH_ENTRY_SAFE(entry
, entry2
, &surface
->renderbuffers
, struct wined3d_renderbuffer_entry
, entry
)
79 TRACE("Deleting renderbuffer %u.\n", entry
->id
);
80 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &entry
->id
);
81 HeapFree(GetProcessHeap(), 0, entry
);
84 context_release(context
);
87 if (surface
->flags
& SFLAG_DIBSECTION
)
89 DeleteDC(surface
->hDC
);
90 DeleteObject(surface
->dib
.DIBsection
);
91 surface
->dib
.bitmap_data
= NULL
;
94 if (surface
->overlay_dest
)
95 list_remove(&surface
->overlay_entry
);
97 LIST_FOR_EACH_ENTRY_SAFE(overlay
, cur
, &surface
->overlays
, struct wined3d_surface
, overlay_entry
)
99 list_remove(&overlay
->overlay_entry
);
100 overlay
->overlay_dest
= NULL
;
103 resource_cleanup(&surface
->resource
);
106 void wined3d_surface_destroy(struct wined3d_surface
*surface
)
108 TRACE("surface %p.\n", surface
);
110 surface_cleanup(surface
);
111 surface
->resource
.parent_ops
->wined3d_object_destroyed(surface
->resource
.parent
);
112 HeapFree(GetProcessHeap(), 0, surface
);
115 void surface_get_drawable_size(const struct wined3d_surface
*surface
, const struct wined3d_context
*context
,
116 unsigned int *width
, unsigned int *height
)
118 if (surface
->container
->swapchain
)
120 /* The drawable size of an onscreen drawable is the surface size.
121 * (Actually: The window size, but the surface is created in window
123 *width
= context
->current_rt
->resource
.width
;
124 *height
= context
->current_rt
->resource
.height
;
126 else if (wined3d_settings
.offscreen_rendering_mode
== ORM_BACKBUFFER
)
128 const struct wined3d_swapchain
*swapchain
= context
->swapchain
;
130 /* The drawable size of a backbuffer / aux buffer offscreen target is
131 * the size of the current context's drawable, which is the size of
132 * the back buffer of the swapchain the active context belongs to. */
133 *width
= swapchain
->desc
.backbuffer_width
;
134 *height
= swapchain
->desc
.backbuffer_height
;
138 /* The drawable size of an FBO target is the OpenGL texture size,
139 * which is the power of two size. */
140 *width
= context
->current_rt
->pow2Width
;
141 *height
= context
->current_rt
->pow2Height
;
149 enum tex_types tex_type
;
150 GLfloat coords
[4][3];
161 static inline void cube_coords_float(const RECT
*r
, UINT w
, UINT h
, struct float_rect
*f
)
163 f
->l
= ((r
->left
* 2.0f
) / w
) - 1.0f
;
164 f
->t
= ((r
->top
* 2.0f
) / h
) - 1.0f
;
165 f
->r
= ((r
->right
* 2.0f
) / w
) - 1.0f
;
166 f
->b
= ((r
->bottom
* 2.0f
) / h
) - 1.0f
;
169 static void surface_get_blt_info(GLenum target
, const RECT
*rect
, GLsizei w
, GLsizei h
, struct blt_info
*info
)
171 GLfloat (*coords
)[3] = info
->coords
;
177 FIXME("Unsupported texture target %#x\n", target
);
178 /* Fall back to GL_TEXTURE_2D */
180 info
->binding
= GL_TEXTURE_BINDING_2D
;
181 info
->bind_target
= GL_TEXTURE_2D
;
182 info
->tex_type
= tex_2d
;
183 coords
[0][0] = (float)rect
->left
/ w
;
184 coords
[0][1] = (float)rect
->top
/ h
;
187 coords
[1][0] = (float)rect
->right
/ w
;
188 coords
[1][1] = (float)rect
->top
/ h
;
191 coords
[2][0] = (float)rect
->left
/ w
;
192 coords
[2][1] = (float)rect
->bottom
/ h
;
195 coords
[3][0] = (float)rect
->right
/ w
;
196 coords
[3][1] = (float)rect
->bottom
/ h
;
200 case GL_TEXTURE_RECTANGLE_ARB
:
201 info
->binding
= GL_TEXTURE_BINDING_RECTANGLE_ARB
;
202 info
->bind_target
= GL_TEXTURE_RECTANGLE_ARB
;
203 info
->tex_type
= tex_rect
;
204 coords
[0][0] = rect
->left
; coords
[0][1] = rect
->top
; coords
[0][2] = 0.0f
;
205 coords
[1][0] = rect
->right
; coords
[1][1] = rect
->top
; coords
[1][2] = 0.0f
;
206 coords
[2][0] = rect
->left
; coords
[2][1] = rect
->bottom
; coords
[2][2] = 0.0f
;
207 coords
[3][0] = rect
->right
; coords
[3][1] = rect
->bottom
; coords
[3][2] = 0.0f
;
210 case GL_TEXTURE_CUBE_MAP_POSITIVE_X
:
211 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
212 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
213 info
->tex_type
= tex_cube
;
214 cube_coords_float(rect
, w
, h
, &f
);
216 coords
[0][0] = 1.0f
; coords
[0][1] = -f
.t
; coords
[0][2] = -f
.l
;
217 coords
[1][0] = 1.0f
; coords
[1][1] = -f
.t
; coords
[1][2] = -f
.r
;
218 coords
[2][0] = 1.0f
; coords
[2][1] = -f
.b
; coords
[2][2] = -f
.l
;
219 coords
[3][0] = 1.0f
; coords
[3][1] = -f
.b
; coords
[3][2] = -f
.r
;
222 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X
:
223 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
224 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
225 info
->tex_type
= tex_cube
;
226 cube_coords_float(rect
, w
, h
, &f
);
228 coords
[0][0] = -1.0f
; coords
[0][1] = -f
.t
; coords
[0][2] = f
.l
;
229 coords
[1][0] = -1.0f
; coords
[1][1] = -f
.t
; coords
[1][2] = f
.r
;
230 coords
[2][0] = -1.0f
; coords
[2][1] = -f
.b
; coords
[2][2] = f
.l
;
231 coords
[3][0] = -1.0f
; coords
[3][1] = -f
.b
; coords
[3][2] = f
.r
;
234 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y
:
235 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
236 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
237 info
->tex_type
= tex_cube
;
238 cube_coords_float(rect
, w
, h
, &f
);
240 coords
[0][0] = f
.l
; coords
[0][1] = 1.0f
; coords
[0][2] = f
.t
;
241 coords
[1][0] = f
.r
; coords
[1][1] = 1.0f
; coords
[1][2] = f
.t
;
242 coords
[2][0] = f
.l
; coords
[2][1] = 1.0f
; coords
[2][2] = f
.b
;
243 coords
[3][0] = f
.r
; coords
[3][1] = 1.0f
; coords
[3][2] = f
.b
;
246 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
:
247 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
248 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
249 info
->tex_type
= tex_cube
;
250 cube_coords_float(rect
, w
, h
, &f
);
252 coords
[0][0] = f
.l
; coords
[0][1] = -1.0f
; coords
[0][2] = -f
.t
;
253 coords
[1][0] = f
.r
; coords
[1][1] = -1.0f
; coords
[1][2] = -f
.t
;
254 coords
[2][0] = f
.l
; coords
[2][1] = -1.0f
; coords
[2][2] = -f
.b
;
255 coords
[3][0] = f
.r
; coords
[3][1] = -1.0f
; coords
[3][2] = -f
.b
;
258 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z
:
259 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
260 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
261 info
->tex_type
= tex_cube
;
262 cube_coords_float(rect
, w
, h
, &f
);
264 coords
[0][0] = f
.l
; coords
[0][1] = -f
.t
; coords
[0][2] = 1.0f
;
265 coords
[1][0] = f
.r
; coords
[1][1] = -f
.t
; coords
[1][2] = 1.0f
;
266 coords
[2][0] = f
.l
; coords
[2][1] = -f
.b
; coords
[2][2] = 1.0f
;
267 coords
[3][0] = f
.r
; coords
[3][1] = -f
.b
; coords
[3][2] = 1.0f
;
270 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
:
271 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
272 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
273 info
->tex_type
= tex_cube
;
274 cube_coords_float(rect
, w
, h
, &f
);
276 coords
[0][0] = -f
.l
; coords
[0][1] = -f
.t
; coords
[0][2] = -1.0f
;
277 coords
[1][0] = -f
.r
; coords
[1][1] = -f
.t
; coords
[1][2] = -1.0f
;
278 coords
[2][0] = -f
.l
; coords
[2][1] = -f
.b
; coords
[2][2] = -1.0f
;
279 coords
[3][0] = -f
.r
; coords
[3][1] = -f
.b
; coords
[3][2] = -1.0f
;
284 static void surface_get_rect(const struct wined3d_surface
*surface
, const RECT
*rect_in
, RECT
*rect_out
)
287 *rect_out
= *rect_in
;
292 rect_out
->right
= surface
->resource
.width
;
293 rect_out
->bottom
= surface
->resource
.height
;
297 /* Context activation is done by the caller. */
298 void draw_textured_quad(const struct wined3d_surface
*src_surface
, struct wined3d_context
*context
,
299 const RECT
*src_rect
, const RECT
*dst_rect
, enum wined3d_texture_filter_type filter
)
301 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
302 struct wined3d_texture
*texture
= src_surface
->container
;
303 struct blt_info info
;
305 surface_get_blt_info(src_surface
->texture_target
, src_rect
, src_surface
->pow2Width
, src_surface
->pow2Height
, &info
);
307 gl_info
->gl_ops
.gl
.p_glEnable(info
.bind_target
);
308 checkGLcall("glEnable(bind_target)");
310 context_bind_texture(context
, info
.bind_target
, texture
->texture_rgb
.name
);
312 /* Filtering for StretchRect */
313 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_MAG_FILTER
,
314 wined3d_gl_mag_filter(magLookup
, filter
));
315 checkGLcall("glTexParameteri");
316 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_MIN_FILTER
,
317 wined3d_gl_min_mip_filter(minMipLookup
, filter
, WINED3D_TEXF_NONE
));
318 checkGLcall("glTexParameteri");
319 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP
);
320 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP
);
321 if (context
->gl_info
->supported
[EXT_TEXTURE_SRGB_DECODE
])
322 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_SRGB_DECODE_EXT
, GL_SKIP_DECODE_EXT
);
323 gl_info
->gl_ops
.gl
.p_glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_REPLACE
);
324 checkGLcall("glTexEnvi");
327 gl_info
->gl_ops
.gl
.p_glBegin(GL_TRIANGLE_STRIP
);
328 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[0]);
329 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
->left
, dst_rect
->top
);
331 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[1]);
332 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
->right
, dst_rect
->top
);
334 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[2]);
335 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
->left
, dst_rect
->bottom
);
337 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[3]);
338 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
->right
, dst_rect
->bottom
);
339 gl_info
->gl_ops
.gl
.p_glEnd();
341 /* Unbind the texture */
342 context_bind_texture(context
, info
.bind_target
, 0);
344 /* We changed the filtering settings on the texture. Inform the
345 * container about this to get the filters reset properly next draw. */
346 texture
->texture_rgb
.states
[WINED3DTEXSTA_MAGFILTER
] = WINED3D_TEXF_POINT
;
347 texture
->texture_rgb
.states
[WINED3DTEXSTA_MINFILTER
] = WINED3D_TEXF_POINT
;
348 texture
->texture_rgb
.states
[WINED3DTEXSTA_MIPFILTER
] = WINED3D_TEXF_NONE
;
349 texture
->texture_rgb
.states
[WINED3DTEXSTA_SRGBTEXTURE
] = FALSE
;
352 /* Works correctly only for <= 4 bpp formats. */
353 static void get_color_masks(const struct wined3d_format
*format
, DWORD
*masks
)
355 masks
[0] = ((1 << format
->red_size
) - 1) << format
->red_offset
;
356 masks
[1] = ((1 << format
->green_size
) - 1) << format
->green_offset
;
357 masks
[2] = ((1 << format
->blue_size
) - 1) << format
->blue_offset
;
360 static HRESULT
surface_create_dib_section(struct wined3d_surface
*surface
)
362 const struct wined3d_format
*format
= surface
->resource
.format
;
368 TRACE("surface %p.\n", surface
);
370 if (!(format
->flags
& WINED3DFMT_FLAG_GETDC
))
372 WARN("Cannot use GetDC on a %s surface.\n", debug_d3dformat(format
->id
));
373 return WINED3DERR_INVALIDCALL
;
376 switch (format
->byte_count
)
380 /* Allocate extra space to store the RGB bit masks. */
381 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
) + 3 * sizeof(DWORD
));
385 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
));
389 /* Allocate extra space for a palette. */
390 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
391 sizeof(BITMAPINFOHEADER
) + sizeof(RGBQUAD
) * (1 << (format
->byte_count
* 8)));
396 return E_OUTOFMEMORY
;
398 /* Some applications access the surface in via DWORDs, and do not take
399 * the necessary care at the end of the surface. So we need at least
400 * 4 extra bytes at the end of the surface. Check against the page size,
401 * if the last page used for the surface has at least 4 spare bytes we're
402 * safe, otherwise add an extra line to the DIB section. */
403 GetSystemInfo(&sysInfo
);
404 if( ((surface
->resource
.size
+ 3) % sysInfo
.dwPageSize
) < 4)
407 TRACE("Adding an extra line to the DIB section.\n");
410 b_info
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
411 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
412 b_info
->bmiHeader
.biWidth
= wined3d_surface_get_pitch(surface
) / format
->byte_count
;
413 b_info
->bmiHeader
.biHeight
= 0 - surface
->resource
.height
- extraline
;
414 b_info
->bmiHeader
.biSizeImage
= (surface
->resource
.height
+ extraline
)
415 * wined3d_surface_get_pitch(surface
);
416 b_info
->bmiHeader
.biPlanes
= 1;
417 b_info
->bmiHeader
.biBitCount
= format
->byte_count
* 8;
419 b_info
->bmiHeader
.biXPelsPerMeter
= 0;
420 b_info
->bmiHeader
.biYPelsPerMeter
= 0;
421 b_info
->bmiHeader
.biClrUsed
= 0;
422 b_info
->bmiHeader
.biClrImportant
= 0;
424 /* Get the bit masks */
425 masks
= (DWORD
*)b_info
->bmiColors
;
426 switch (surface
->resource
.format
->id
)
428 case WINED3DFMT_B8G8R8_UNORM
:
429 b_info
->bmiHeader
.biCompression
= BI_RGB
;
432 case WINED3DFMT_B5G5R5X1_UNORM
:
433 case WINED3DFMT_B5G5R5A1_UNORM
:
434 case WINED3DFMT_B4G4R4A4_UNORM
:
435 case WINED3DFMT_B4G4R4X4_UNORM
:
436 case WINED3DFMT_B2G3R3_UNORM
:
437 case WINED3DFMT_B2G3R3A8_UNORM
:
438 case WINED3DFMT_R10G10B10A2_UNORM
:
439 case WINED3DFMT_R8G8B8A8_UNORM
:
440 case WINED3DFMT_R8G8B8X8_UNORM
:
441 case WINED3DFMT_B10G10R10A2_UNORM
:
442 case WINED3DFMT_B5G6R5_UNORM
:
443 case WINED3DFMT_R16G16B16A16_UNORM
:
444 b_info
->bmiHeader
.biCompression
= BI_BITFIELDS
;
445 get_color_masks(format
, masks
);
449 /* Don't know palette */
450 b_info
->bmiHeader
.biCompression
= BI_RGB
;
454 TRACE("Creating a DIB section with size %dx%dx%d, size=%d.\n",
455 b_info
->bmiHeader
.biWidth
, b_info
->bmiHeader
.biHeight
,
456 b_info
->bmiHeader
.biBitCount
, b_info
->bmiHeader
.biSizeImage
);
457 surface
->dib
.DIBsection
= CreateDIBSection(0, b_info
, DIB_RGB_COLORS
, &surface
->dib
.bitmap_data
, 0, 0);
459 if (!surface
->dib
.DIBsection
)
461 ERR("Failed to create DIB section.\n");
462 HeapFree(GetProcessHeap(), 0, b_info
);
463 return HRESULT_FROM_WIN32(GetLastError());
466 TRACE("DIBSection at %p.\n", surface
->dib
.bitmap_data
);
467 surface
->dib
.bitmap_size
= b_info
->bmiHeader
.biSizeImage
;
469 HeapFree(GetProcessHeap(), 0, b_info
);
471 /* Now allocate a DC. */
472 surface
->hDC
= CreateCompatibleDC(0);
473 SelectObject(surface
->hDC
, surface
->dib
.DIBsection
);
475 surface
->flags
|= SFLAG_DIBSECTION
;
480 static void surface_get_memory(const struct wined3d_surface
*surface
, struct wined3d_bo_address
*data
,
483 if (location
& WINED3D_LOCATION_BUFFER
)
486 data
->buffer_object
= surface
->pbo
;
489 if (location
& WINED3D_LOCATION_USER_MEMORY
)
491 data
->addr
= surface
->user_memory
;
492 data
->buffer_object
= 0;
495 if (location
& WINED3D_LOCATION_DIB
)
497 data
->addr
= surface
->dib
.bitmap_data
;
498 data
->buffer_object
= 0;
501 if (location
& WINED3D_LOCATION_SYSMEM
)
503 data
->addr
= surface
->resource
.heap_memory
;
504 data
->buffer_object
= 0;
508 ERR("Unexpected locations %s.\n", wined3d_debug_location(location
));
510 data
->buffer_object
= 0;
513 static void surface_prepare_buffer(struct wined3d_surface
*surface
)
515 struct wined3d_context
*context
;
517 const struct wined3d_gl_info
*gl_info
;
522 context
= context_acquire(surface
->resource
.device
, NULL
);
523 gl_info
= context
->gl_info
;
525 GL_EXTCALL(glGenBuffersARB(1, &surface
->pbo
));
526 error
= gl_info
->gl_ops
.gl
.p_glGetError();
527 if (!surface
->pbo
|| error
!= GL_NO_ERROR
)
528 ERR("Failed to create a PBO with error %s (%#x).\n", debug_glerror(error
), error
);
530 TRACE("Binding PBO %u.\n", surface
->pbo
);
532 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->pbo
));
533 checkGLcall("glBindBufferARB");
535 GL_EXTCALL(glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->resource
.size
+ 4,
536 NULL
, GL_STREAM_DRAW_ARB
));
537 checkGLcall("glBufferDataARB");
539 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
540 checkGLcall("glBindBufferARB");
542 context_release(context
);
545 static void surface_prepare_system_memory(struct wined3d_surface
*surface
)
547 TRACE("surface %p.\n", surface
);
549 if (surface
->resource
.heap_memory
)
552 /* Whatever surface we have, make sure that there is memory allocated
553 * for the downloaded copy, or a PBO to map. */
554 if (!wined3d_resource_allocate_sysmem(&surface
->resource
))
555 ERR("Failed to allocate system memory.\n");
557 if (surface
->locations
& WINED3D_LOCATION_SYSMEM
)
558 ERR("Surface without system memory has WINED3D_LOCATION_SYSMEM set.\n");
561 void surface_prepare_map_memory(struct wined3d_surface
*surface
)
563 switch (surface
->resource
.map_binding
)
565 case WINED3D_LOCATION_SYSMEM
:
566 surface_prepare_system_memory(surface
);
569 case WINED3D_LOCATION_USER_MEMORY
:
570 if (!surface
->user_memory
)
571 ERR("Map binding is set to WINED3D_LOCATION_USER_MEMORY but surface->user_memory is NULL.\n");
574 case WINED3D_LOCATION_DIB
:
575 if (!surface
->dib
.bitmap_data
)
576 ERR("Map binding is set to WINED3D_LOCATION_DIB but surface->dib.bitmap_data is NULL.\n");
579 case WINED3D_LOCATION_BUFFER
:
580 surface_prepare_buffer(surface
);
584 ERR("Unexpected map binding %s.\n", wined3d_debug_location(surface
->resource
.map_binding
));
588 static void surface_evict_sysmem(struct wined3d_surface
*surface
)
590 /* In some conditions the surface memory must not be freed:
591 * SFLAG_CONVERTED: Converting the data back would take too long
592 * SFLAG_DYNLOCK: Avoid freeing the data for performance
593 * SFLAG_CLIENT: OpenGL uses our memory as backup */
594 if (surface
->resource
.map_count
|| surface
->flags
& (SFLAG_CONVERTED
| SFLAG_DYNLOCK
595 | SFLAG_CLIENT
| SFLAG_PIN_SYSMEM
))
598 wined3d_resource_free_sysmem(&surface
->resource
);
599 surface_invalidate_location(surface
, WINED3D_LOCATION_SYSMEM
);
602 static void surface_force_reload(struct wined3d_surface
*surface
)
604 surface
->flags
&= ~(SFLAG_ALLOCATED
| SFLAG_SRGBALLOCATED
);
607 static void surface_release_client_storage(struct wined3d_surface
*surface
)
609 struct wined3d_context
*context
= context_acquire(surface
->resource
.device
, NULL
);
610 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
612 if (surface
->container
->texture_rgb
.name
)
614 wined3d_texture_bind_and_dirtify(surface
->container
, context
, FALSE
);
615 gl_info
->gl_ops
.gl
.p_glTexImage2D(surface
->texture_target
, surface
->texture_level
,
616 GL_RGB
, 1, 1, 0, GL_RGB
, GL_UNSIGNED_BYTE
, NULL
);
618 if (surface
->container
->texture_srgb
.name
)
620 wined3d_texture_bind_and_dirtify(surface
->container
, context
, TRUE
);
621 gl_info
->gl_ops
.gl
.p_glTexImage2D(surface
->texture_target
, surface
->texture_level
,
622 GL_RGB
, 1, 1, 0, GL_RGB
, GL_UNSIGNED_BYTE
, NULL
);
625 context_release(context
);
627 surface_invalidate_location(surface
, WINED3D_LOCATION_TEXTURE_RGB
| WINED3D_LOCATION_TEXTURE_SRGB
);
628 surface_force_reload(surface
);
631 static BOOL
surface_use_pbo(const struct wined3d_surface
*surface
)
633 const struct wined3d_gl_info
*gl_info
= &surface
->resource
.device
->adapter
->gl_info
;
635 return surface
->resource
.pool
== WINED3D_POOL_DEFAULT
636 && surface
->resource
.access_flags
& WINED3D_RESOURCE_ACCESS_CPU
637 && gl_info
->supported
[ARB_PIXEL_BUFFER_OBJECT
]
638 && !surface
->resource
.format
->convert
639 && !(surface
->flags
& (SFLAG_NONPOW2
| SFLAG_PIN_SYSMEM
));
642 static HRESULT
surface_private_setup(struct wined3d_surface
*surface
)
644 /* TODO: Check against the maximum texture sizes supported by the video card. */
645 const struct wined3d_gl_info
*gl_info
= &surface
->resource
.device
->adapter
->gl_info
;
646 unsigned int pow2Width
, pow2Height
;
648 TRACE("surface %p.\n", surface
);
650 /* Non-power2 support */
651 if (gl_info
->supported
[ARB_TEXTURE_NON_POWER_OF_TWO
] || gl_info
->supported
[WINED3D_GL_NORMALIZED_TEXRECT
]
652 || gl_info
->supported
[ARB_TEXTURE_RECTANGLE
])
654 pow2Width
= surface
->resource
.width
;
655 pow2Height
= surface
->resource
.height
;
659 /* Find the nearest pow2 match */
660 pow2Width
= pow2Height
= 1;
661 while (pow2Width
< surface
->resource
.width
)
663 while (pow2Height
< surface
->resource
.height
)
666 surface
->pow2Width
= pow2Width
;
667 surface
->pow2Height
= pow2Height
;
669 if (pow2Width
> surface
->resource
.width
|| pow2Height
> surface
->resource
.height
)
671 /* TODO: Add support for non power two compressed textures. */
672 if (surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_COMPRESSED
| WINED3DFMT_FLAG_HEIGHT_SCALE
))
674 FIXME("(%p) Compressed or height scaled non-power-two textures are not supported w(%d) h(%d)\n",
675 surface
, surface
->resource
.width
, surface
->resource
.height
);
676 return WINED3DERR_NOTAVAILABLE
;
680 if (pow2Width
!= surface
->resource
.width
681 || pow2Height
!= surface
->resource
.height
)
683 surface
->flags
|= SFLAG_NONPOW2
;
686 if ((surface
->pow2Width
> gl_info
->limits
.texture_size
|| surface
->pow2Height
> gl_info
->limits
.texture_size
)
687 && !(surface
->resource
.usage
& (WINED3DUSAGE_RENDERTARGET
| WINED3DUSAGE_DEPTHSTENCIL
)))
689 /* One of three options:
690 * 1: Do the same as we do with NPOT and scale the texture, (any
691 * texture ops would require the texture to be scaled which is
693 * 2: Set the texture to the maximum size (bad idea).
694 * 3: WARN and return WINED3DERR_NOTAVAILABLE;
695 * 4: Create the surface, but allow it to be used only for DirectDraw
696 * Blts. Some apps (e.g. Swat 3) create textures with a Height of
697 * 16 and a Width > 3000 and blt 16x16 letter areas from them to
698 * the render target. */
699 if (surface
->resource
.pool
== WINED3D_POOL_DEFAULT
|| surface
->resource
.pool
== WINED3D_POOL_MANAGED
)
701 WARN("Unable to allocate a surface which exceeds the maximum OpenGL texture size.\n");
702 return WINED3DERR_NOTAVAILABLE
;
705 /* We should never use this surface in combination with OpenGL! */
706 TRACE("Creating an oversized surface: %ux%u.\n",
707 surface
->pow2Width
, surface
->pow2Height
);
710 if (surface
->resource
.usage
& WINED3DUSAGE_DEPTHSTENCIL
)
711 surface
->locations
= WINED3D_LOCATION_DISCARDED
;
713 if (surface_use_pbo(surface
))
714 surface
->resource
.map_binding
= WINED3D_LOCATION_BUFFER
;
719 static void surface_unmap(struct wined3d_surface
*surface
)
721 struct wined3d_device
*device
= surface
->resource
.device
;
722 const struct wined3d_gl_info
*gl_info
;
723 struct wined3d_context
*context
;
725 TRACE("surface %p.\n", surface
);
727 memset(&surface
->lockedRect
, 0, sizeof(surface
->lockedRect
));
729 switch (surface
->resource
.map_binding
)
731 case WINED3D_LOCATION_SYSMEM
:
732 case WINED3D_LOCATION_USER_MEMORY
:
733 case WINED3D_LOCATION_DIB
:
736 case WINED3D_LOCATION_BUFFER
:
737 context
= context_acquire(device
, NULL
);
738 gl_info
= context
->gl_info
;
740 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->pbo
));
741 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
));
742 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
743 checkGLcall("glUnmapBufferARB");
744 context_release(context
);
748 ERR("Unexpected map binding %s.\n", wined3d_debug_location(surface
->resource
.map_binding
));
751 if (surface
->locations
& (WINED3D_LOCATION_DRAWABLE
| WINED3D_LOCATION_TEXTURE_RGB
))
753 TRACE("Not dirtified, nothing to do.\n");
757 if (surface
->container
->swapchain
&& surface
->container
->swapchain
->front_buffer
== surface
->container
)
758 surface_load_location(surface
, surface
->container
->resource
.draw_binding
);
759 else if (surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
))
760 FIXME("Depth / stencil buffer locking is not implemented.\n");
763 static BOOL
surface_is_full_rect(const struct wined3d_surface
*surface
, const RECT
*r
)
765 if ((r
->left
&& r
->right
) || abs(r
->right
- r
->left
) != surface
->resource
.width
)
767 if ((r
->top
&& r
->bottom
) || abs(r
->bottom
- r
->top
) != surface
->resource
.height
)
772 static void surface_depth_blt_fbo(const struct wined3d_device
*device
,
773 struct wined3d_surface
*src_surface
, DWORD src_location
, const RECT
*src_rect
,
774 struct wined3d_surface
*dst_surface
, DWORD dst_location
, const RECT
*dst_rect
)
776 const struct wined3d_gl_info
*gl_info
;
777 struct wined3d_context
*context
;
778 DWORD src_mask
, dst_mask
;
781 TRACE("device %p\n", device
);
782 TRACE("src_surface %p, src_location %s, src_rect %s,\n",
783 src_surface
, wined3d_debug_location(src_location
), wine_dbgstr_rect(src_rect
));
784 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
785 dst_surface
, wined3d_debug_location(dst_location
), wine_dbgstr_rect(dst_rect
));
787 src_mask
= src_surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
788 dst_mask
= dst_surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
790 if (src_mask
!= dst_mask
)
792 ERR("Incompatible formats %s and %s.\n",
793 debug_d3dformat(src_surface
->resource
.format
->id
),
794 debug_d3dformat(dst_surface
->resource
.format
->id
));
800 ERR("Not a depth / stencil format: %s.\n",
801 debug_d3dformat(src_surface
->resource
.format
->id
));
806 if (src_mask
& WINED3DFMT_FLAG_DEPTH
)
807 gl_mask
|= GL_DEPTH_BUFFER_BIT
;
808 if (src_mask
& WINED3DFMT_FLAG_STENCIL
)
809 gl_mask
|= GL_STENCIL_BUFFER_BIT
;
811 /* Make sure the locations are up-to-date. Loading the destination
812 * surface isn't required if the entire surface is overwritten. */
813 surface_load_location(src_surface
, src_location
);
814 if (!surface_is_full_rect(dst_surface
, dst_rect
))
815 surface_load_location(dst_surface
, dst_location
);
817 context
= context_acquire(device
, NULL
);
820 context_release(context
);
821 WARN("Invalid context, skipping blit.\n");
825 gl_info
= context
->gl_info
;
827 context_apply_fbo_state_blit(context
, GL_READ_FRAMEBUFFER
, NULL
, src_surface
, src_location
);
828 context_check_fbo_status(context
, GL_READ_FRAMEBUFFER
);
830 context_apply_fbo_state_blit(context
, GL_DRAW_FRAMEBUFFER
, NULL
, dst_surface
, dst_location
);
831 context_set_draw_buffer(context
, GL_NONE
);
832 context_check_fbo_status(context
, GL_DRAW_FRAMEBUFFER
);
833 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
835 if (gl_mask
& GL_DEPTH_BUFFER_BIT
)
837 gl_info
->gl_ops
.gl
.p_glDepthMask(GL_TRUE
);
838 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_ZWRITEENABLE
));
840 if (gl_mask
& GL_STENCIL_BUFFER_BIT
)
842 if (context
->gl_info
->supported
[EXT_STENCIL_TWO_SIDE
])
844 gl_info
->gl_ops
.gl
.p_glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT
);
845 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_TWOSIDEDSTENCILMODE
));
847 gl_info
->gl_ops
.gl
.p_glStencilMask(~0U);
848 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK
));
851 gl_info
->gl_ops
.gl
.p_glDisable(GL_SCISSOR_TEST
);
852 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE
));
854 gl_info
->fbo_ops
.glBlitFramebuffer(src_rect
->left
, src_rect
->top
, src_rect
->right
, src_rect
->bottom
,
855 dst_rect
->left
, dst_rect
->top
, dst_rect
->right
, dst_rect
->bottom
, gl_mask
, GL_NEAREST
);
856 checkGLcall("glBlitFramebuffer()");
858 if (wined3d_settings
.strict_draw_ordering
)
859 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
861 context_release(context
);
864 /* Blit between surface locations. Onscreen on different swapchains is not supported.
865 * Depth / stencil is not supported. */
866 static void surface_blt_fbo(const struct wined3d_device
*device
, enum wined3d_texture_filter_type filter
,
867 struct wined3d_surface
*src_surface
, DWORD src_location
, const RECT
*src_rect_in
,
868 struct wined3d_surface
*dst_surface
, DWORD dst_location
, const RECT
*dst_rect_in
)
870 const struct wined3d_gl_info
*gl_info
;
871 struct wined3d_context
*context
;
872 RECT src_rect
, dst_rect
;
876 TRACE("device %p, filter %s,\n", device
, debug_d3dtexturefiltertype(filter
));
877 TRACE("src_surface %p, src_location %s, src_rect %s,\n",
878 src_surface
, wined3d_debug_location(src_location
), wine_dbgstr_rect(src_rect_in
));
879 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
880 dst_surface
, wined3d_debug_location(dst_location
), wine_dbgstr_rect(dst_rect_in
));
882 src_rect
= *src_rect_in
;
883 dst_rect
= *dst_rect_in
;
887 case WINED3D_TEXF_LINEAR
:
888 gl_filter
= GL_LINEAR
;
892 FIXME("Unsupported filter mode %s (%#x).\n", debug_d3dtexturefiltertype(filter
), filter
);
893 case WINED3D_TEXF_NONE
:
894 case WINED3D_TEXF_POINT
:
895 gl_filter
= GL_NEAREST
;
899 /* Resolve the source surface first if needed. */
900 if (src_location
== WINED3D_LOCATION_RB_MULTISAMPLE
901 && (src_surface
->resource
.format
->id
!= dst_surface
->resource
.format
->id
902 || abs(src_rect
.bottom
- src_rect
.top
) != abs(dst_rect
.bottom
- dst_rect
.top
)
903 || abs(src_rect
.right
- src_rect
.left
) != abs(dst_rect
.right
- dst_rect
.left
)))
904 src_location
= WINED3D_LOCATION_RB_RESOLVED
;
906 /* Make sure the locations are up-to-date. Loading the destination
907 * surface isn't required if the entire surface is overwritten. (And is
908 * in fact harmful if we're being called by surface_load_location() with
909 * the purpose of loading the destination surface.) */
910 surface_load_location(src_surface
, src_location
);
911 if (!surface_is_full_rect(dst_surface
, &dst_rect
))
912 surface_load_location(dst_surface
, dst_location
);
914 if (src_location
== WINED3D_LOCATION_DRAWABLE
) context
= context_acquire(device
, src_surface
);
915 else if (dst_location
== WINED3D_LOCATION_DRAWABLE
) context
= context_acquire(device
, dst_surface
);
916 else context
= context_acquire(device
, NULL
);
920 context_release(context
);
921 WARN("Invalid context, skipping blit.\n");
925 gl_info
= context
->gl_info
;
927 if (src_location
== WINED3D_LOCATION_DRAWABLE
)
929 TRACE("Source surface %p is onscreen.\n", src_surface
);
930 buffer
= surface_get_gl_buffer(src_surface
);
931 surface_translate_drawable_coords(src_surface
, context
->win_handle
, &src_rect
);
935 TRACE("Source surface %p is offscreen.\n", src_surface
);
936 buffer
= GL_COLOR_ATTACHMENT0
;
939 context_apply_fbo_state_blit(context
, GL_READ_FRAMEBUFFER
, src_surface
, NULL
, src_location
);
940 gl_info
->gl_ops
.gl
.p_glReadBuffer(buffer
);
941 checkGLcall("glReadBuffer()");
942 context_check_fbo_status(context
, GL_READ_FRAMEBUFFER
);
944 if (dst_location
== WINED3D_LOCATION_DRAWABLE
)
946 TRACE("Destination surface %p is onscreen.\n", dst_surface
);
947 buffer
= surface_get_gl_buffer(dst_surface
);
948 surface_translate_drawable_coords(dst_surface
, context
->win_handle
, &dst_rect
);
952 TRACE("Destination surface %p is offscreen.\n", dst_surface
);
953 buffer
= GL_COLOR_ATTACHMENT0
;
956 context_apply_fbo_state_blit(context
, GL_DRAW_FRAMEBUFFER
, dst_surface
, NULL
, dst_location
);
957 context_set_draw_buffer(context
, buffer
);
958 context_check_fbo_status(context
, GL_DRAW_FRAMEBUFFER
);
959 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
961 gl_info
->gl_ops
.gl
.p_glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
962 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE
));
963 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE1
));
964 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE2
));
965 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE3
));
967 gl_info
->gl_ops
.gl
.p_glDisable(GL_SCISSOR_TEST
);
968 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE
));
970 gl_info
->fbo_ops
.glBlitFramebuffer(src_rect
.left
, src_rect
.top
, src_rect
.right
, src_rect
.bottom
,
971 dst_rect
.left
, dst_rect
.top
, dst_rect
.right
, dst_rect
.bottom
, GL_COLOR_BUFFER_BIT
, gl_filter
);
972 checkGLcall("glBlitFramebuffer()");
974 if (wined3d_settings
.strict_draw_ordering
975 || (dst_location
== WINED3D_LOCATION_DRAWABLE
976 && dst_surface
->container
->swapchain
->front_buffer
== dst_surface
->container
))
977 gl_info
->gl_ops
.gl
.p_glFlush();
979 context_release(context
);
982 static BOOL
fbo_blit_supported(const struct wined3d_gl_info
*gl_info
, enum wined3d_blit_op blit_op
,
983 const RECT
*src_rect
, DWORD src_usage
, enum wined3d_pool src_pool
, const struct wined3d_format
*src_format
,
984 const RECT
*dst_rect
, DWORD dst_usage
, enum wined3d_pool dst_pool
, const struct wined3d_format
*dst_format
)
986 if ((wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
) || !gl_info
->fbo_ops
.glBlitFramebuffer
)
989 /* Source and/or destination need to be on the GL side */
990 if (src_pool
== WINED3D_POOL_SYSTEM_MEM
|| dst_pool
== WINED3D_POOL_SYSTEM_MEM
)
995 case WINED3D_BLIT_OP_COLOR_BLIT
:
996 if (!((src_format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE
) || (src_usage
& WINED3DUSAGE_RENDERTARGET
)))
998 if (!((dst_format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE
) || (dst_usage
& WINED3DUSAGE_RENDERTARGET
)))
1002 case WINED3D_BLIT_OP_DEPTH_BLIT
:
1003 if (!(src_format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
)))
1005 if (!(dst_format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
)))
1013 if (!(src_format
->id
== dst_format
->id
1014 || (is_identity_fixup(src_format
->color_fixup
)
1015 && is_identity_fixup(dst_format
->color_fixup
))))
1021 static BOOL
surface_convert_color_to_float(const struct wined3d_surface
*surface
,
1022 DWORD color
, struct wined3d_color
*float_color
)
1024 const struct wined3d_format
*format
= surface
->resource
.format
;
1025 const struct wined3d_palette
*palette
;
1029 case WINED3DFMT_P8_UINT
:
1030 palette
= surface
->container
->swapchain
? surface
->container
->swapchain
->palette
: NULL
;
1034 float_color
->r
= palette
->colors
[color
].rgbRed
/ 255.0f
;
1035 float_color
->g
= palette
->colors
[color
].rgbGreen
/ 255.0f
;
1036 float_color
->b
= palette
->colors
[color
].rgbBlue
/ 255.0f
;
1040 float_color
->r
= 0.0f
;
1041 float_color
->g
= 0.0f
;
1042 float_color
->b
= 0.0f
;
1044 float_color
->a
= color
/ 255.0f
;
1047 case WINED3DFMT_B5G6R5_UNORM
:
1048 float_color
->r
= ((color
>> 11) & 0x1f) / 31.0f
;
1049 float_color
->g
= ((color
>> 5) & 0x3f) / 63.0f
;
1050 float_color
->b
= (color
& 0x1f) / 31.0f
;
1051 float_color
->a
= 1.0f
;
1054 case WINED3DFMT_B8G8R8_UNORM
:
1055 case WINED3DFMT_B8G8R8X8_UNORM
:
1056 float_color
->r
= D3DCOLOR_R(color
);
1057 float_color
->g
= D3DCOLOR_G(color
);
1058 float_color
->b
= D3DCOLOR_B(color
);
1059 float_color
->a
= 1.0f
;
1062 case WINED3DFMT_B8G8R8A8_UNORM
:
1063 float_color
->r
= D3DCOLOR_R(color
);
1064 float_color
->g
= D3DCOLOR_G(color
);
1065 float_color
->b
= D3DCOLOR_B(color
);
1066 float_color
->a
= D3DCOLOR_A(color
);
1070 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format
->id
));
1077 static BOOL
surface_convert_depth_to_float(const struct wined3d_surface
*surface
, DWORD depth
, float *float_depth
)
1079 const struct wined3d_format
*format
= surface
->resource
.format
;
1083 case WINED3DFMT_S1_UINT_D15_UNORM
:
1084 *float_depth
= depth
/ (float)0x00007fff;
1087 case WINED3DFMT_D16_UNORM
:
1088 *float_depth
= depth
/ (float)0x0000ffff;
1091 case WINED3DFMT_D24_UNORM_S8_UINT
:
1092 case WINED3DFMT_X8D24_UNORM
:
1093 *float_depth
= depth
/ (float)0x00ffffff;
1096 case WINED3DFMT_D32_UNORM
:
1097 *float_depth
= depth
/ (float)0xffffffff;
1101 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format
->id
));
1108 static HRESULT
wined3d_surface_depth_fill(struct wined3d_surface
*surface
, const RECT
*rect
, float depth
)
1110 const struct wined3d_resource
*resource
= &surface
->container
->resource
;
1111 struct wined3d_device
*device
= resource
->device
;
1112 const struct blit_shader
*blitter
;
1114 blitter
= wined3d_select_blitter(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_DEPTH_FILL
,
1115 NULL
, 0, 0, NULL
, rect
, resource
->usage
, resource
->pool
, resource
->format
);
1118 FIXME("No blitter is capable of performing the requested depth fill operation.\n");
1119 return WINED3DERR_INVALIDCALL
;
1122 return blitter
->depth_fill(device
, surface
, rect
, depth
);
1125 static HRESULT
wined3d_surface_depth_blt(struct wined3d_surface
*src_surface
, DWORD src_location
, const RECT
*src_rect
,
1126 struct wined3d_surface
*dst_surface
, DWORD dst_location
, const RECT
*dst_rect
)
1128 struct wined3d_device
*device
= src_surface
->resource
.device
;
1130 if (!fbo_blit_supported(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_DEPTH_BLIT
,
1131 src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
1132 dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
))
1133 return WINED3DERR_INVALIDCALL
;
1135 surface_depth_blt_fbo(device
, src_surface
, src_location
, src_rect
, dst_surface
, dst_location
, dst_rect
);
1137 surface_modify_ds_location(dst_surface
, dst_location
,
1138 dst_surface
->ds_current_size
.cx
, dst_surface
->ds_current_size
.cy
);
1143 HRESULT CDECL
wined3d_surface_get_render_target_data(struct wined3d_surface
*surface
,
1144 struct wined3d_surface
*render_target
)
1146 TRACE("surface %p, render_target %p.\n", surface
, render_target
);
1148 /* TODO: Check surface sizes, pools, etc. */
1150 if (render_target
->resource
.multisample_type
)
1151 return WINED3DERR_INVALIDCALL
;
1153 return wined3d_surface_blt(surface
, NULL
, render_target
, NULL
, 0, NULL
, WINED3D_TEXF_POINT
);
1156 /* Context activation is done by the caller. */
1157 static void surface_remove_pbo(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
)
1159 GL_EXTCALL(glDeleteBuffersARB(1, &surface
->pbo
));
1160 checkGLcall("glDeleteBuffersARB(1, &surface->pbo)");
1163 surface_invalidate_location(surface
, WINED3D_LOCATION_BUFFER
);
1166 static ULONG
surface_resource_incref(struct wined3d_resource
*resource
)
1168 return wined3d_surface_incref(surface_from_resource(resource
));
1171 static ULONG
surface_resource_decref(struct wined3d_resource
*resource
)
1173 return wined3d_surface_decref(surface_from_resource(resource
));
1176 static void surface_unload(struct wined3d_resource
*resource
)
1178 struct wined3d_surface
*surface
= surface_from_resource(resource
);
1179 struct wined3d_renderbuffer_entry
*entry
, *entry2
;
1180 struct wined3d_device
*device
= resource
->device
;
1181 const struct wined3d_gl_info
*gl_info
;
1182 struct wined3d_context
*context
;
1184 TRACE("surface %p.\n", surface
);
1186 if (resource
->pool
== WINED3D_POOL_DEFAULT
)
1188 /* Default pool resources are supposed to be destroyed before Reset is called.
1189 * Implicit resources stay however. So this means we have an implicit render target
1190 * or depth stencil. The content may be destroyed, but we still have to tear down
1191 * opengl resources, so we cannot leave early.
1193 * Put the surfaces into sysmem, and reset the content. The D3D content is undefined,
1194 * but we can't set the sysmem INDRAWABLE because when we're rendering the swapchain
1195 * or the depth stencil into an FBO the texture or render buffer will be removed
1196 * and all flags get lost */
1197 surface_prepare_system_memory(surface
);
1198 memset(surface
->resource
.heap_memory
, 0, surface
->resource
.size
);
1199 surface_validate_location(surface
, WINED3D_LOCATION_SYSMEM
);
1200 surface_invalidate_location(surface
, ~WINED3D_LOCATION_SYSMEM
);
1202 /* We also get here when the ddraw swapchain is destroyed, for example
1203 * for a mode switch. In this case this surface won't necessarily be
1204 * an implicit surface. We have to mark it lost so that the
1205 * application can restore it after the mode switch. */
1206 surface
->flags
|= SFLAG_LOST
;
1210 surface_prepare_map_memory(surface
);
1211 surface_load_location(surface
, surface
->resource
.map_binding
);
1212 surface_invalidate_location(surface
, ~surface
->resource
.map_binding
);
1214 surface
->flags
&= ~(SFLAG_ALLOCATED
| SFLAG_SRGBALLOCATED
);
1216 context
= context_acquire(device
, NULL
);
1217 gl_info
= context
->gl_info
;
1219 /* Destroy PBOs, but load them into real sysmem before */
1221 surface_remove_pbo(surface
, gl_info
);
1223 /* Destroy fbo render buffers. This is needed for implicit render targets, for
1224 * all application-created targets the application has to release the surface
1225 * before calling _Reset
1227 LIST_FOR_EACH_ENTRY_SAFE(entry
, entry2
, &surface
->renderbuffers
, struct wined3d_renderbuffer_entry
, entry
)
1229 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &entry
->id
);
1230 list_remove(&entry
->entry
);
1231 HeapFree(GetProcessHeap(), 0, entry
);
1233 list_init(&surface
->renderbuffers
);
1234 surface
->current_renderbuffer
= NULL
;
1236 if (surface
->rb_multisample
)
1238 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &surface
->rb_multisample
);
1239 surface
->rb_multisample
= 0;
1241 if (surface
->rb_resolved
)
1243 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &surface
->rb_resolved
);
1244 surface
->rb_resolved
= 0;
1247 context_release(context
);
1249 resource_unload(resource
);
1252 static const struct wined3d_resource_ops surface_resource_ops
=
1254 surface_resource_incref
,
1255 surface_resource_decref
,
1259 static const struct wined3d_surface_ops surface_ops
=
1261 surface_private_setup
,
1265 /*****************************************************************************
1266 * Initializes the GDI surface, aka creates the DIB section we render to
1267 * The DIB section creation is done by calling GetDC, which will create the
1268 * section and releasing the dc to allow the app to use it. The dib section
1269 * will stay until the surface is released
1271 * GDI surfaces do not need to be a power of 2 in size, so the pow2 sizes
1272 * are set to the real sizes to save memory. The NONPOW2 flag is unset to
1273 * avoid confusion in the shared surface code.
1276 * WINED3D_OK on success
1277 * The return values of called methods on failure
1279 *****************************************************************************/
1280 static HRESULT
gdi_surface_private_setup(struct wined3d_surface
*surface
)
1284 TRACE("surface %p.\n", surface
);
1286 if (surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
)
1288 ERR("Overlays not yet supported by GDI surfaces.\n");
1289 return WINED3DERR_INVALIDCALL
;
1292 /* Sysmem textures have memory already allocated - release it,
1293 * this avoids an unnecessary memcpy. */
1294 hr
= surface_create_dib_section(surface
);
1297 surface
->resource
.map_binding
= WINED3D_LOCATION_DIB
;
1299 /* We don't mind the nonpow2 stuff in GDI. */
1300 surface
->pow2Width
= surface
->resource
.width
;
1301 surface
->pow2Height
= surface
->resource
.height
;
1306 static void gdi_surface_unmap(struct wined3d_surface
*surface
)
1308 TRACE("surface %p.\n", surface
);
1310 /* Tell the swapchain to update the screen. */
1311 if (surface
->container
->swapchain
&& surface
->container
== surface
->container
->swapchain
->front_buffer
)
1312 x11_copy_to_screen(surface
->container
->swapchain
, &surface
->lockedRect
);
1314 memset(&surface
->lockedRect
, 0, sizeof(RECT
));
1317 static const struct wined3d_surface_ops gdi_surface_ops
=
1319 gdi_surface_private_setup
,
1323 /* This call just downloads data, the caller is responsible for binding the
1324 * correct texture. */
1325 /* Context activation is done by the caller. */
1326 static void surface_download_data(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
,
1329 const struct wined3d_format
*format
= surface
->resource
.format
;
1330 struct wined3d_bo_address data
;
1332 /* Only support read back of converted P8 surfaces. */
1333 if (surface
->flags
& SFLAG_CONVERTED
&& format
->id
!= WINED3DFMT_P8_UINT
)
1335 ERR("Trying to read back converted surface %p with format %s.\n", surface
, debug_d3dformat(format
->id
));
1339 surface_get_memory(surface
, &data
, dst_location
);
1341 if (format
->flags
& WINED3DFMT_FLAG_COMPRESSED
)
1343 TRACE("(%p) : Calling glGetCompressedTexImageARB level %d, format %#x, type %#x, data %p.\n",
1344 surface
, surface
->texture_level
, format
->glFormat
, format
->glType
, data
.addr
);
1346 if (data
.buffer_object
)
1348 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, data
.buffer_object
));
1349 checkGLcall("glBindBufferARB");
1350 GL_EXTCALL(glGetCompressedTexImageARB(surface
->texture_target
, surface
->texture_level
, NULL
));
1351 checkGLcall("glGetCompressedTexImageARB");
1352 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, 0));
1353 checkGLcall("glBindBufferARB");
1357 GL_EXTCALL(glGetCompressedTexImageARB(surface
->texture_target
,
1358 surface
->texture_level
, data
.addr
));
1359 checkGLcall("glGetCompressedTexImageARB");
1365 GLenum gl_format
= format
->glFormat
;
1366 GLenum gl_type
= format
->glType
;
1370 if (surface
->flags
& SFLAG_NONPOW2
)
1372 unsigned char alignment
= surface
->resource
.device
->surface_alignment
;
1373 src_pitch
= format
->byte_count
* surface
->pow2Width
;
1374 dst_pitch
= wined3d_surface_get_pitch(surface
);
1375 src_pitch
= (src_pitch
+ alignment
- 1) & ~(alignment
- 1);
1376 mem
= HeapAlloc(GetProcessHeap(), 0, src_pitch
* surface
->pow2Height
);
1383 TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n",
1384 surface
, surface
->texture_level
, gl_format
, gl_type
, mem
);
1386 if (data
.buffer_object
)
1388 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, data
.buffer_object
));
1389 checkGLcall("glBindBufferARB");
1391 gl_info
->gl_ops
.gl
.p_glGetTexImage(surface
->texture_target
, surface
->texture_level
,
1392 gl_format
, gl_type
, NULL
);
1393 checkGLcall("glGetTexImage");
1395 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, 0));
1396 checkGLcall("glBindBufferARB");
1400 gl_info
->gl_ops
.gl
.p_glGetTexImage(surface
->texture_target
, surface
->texture_level
,
1401 gl_format
, gl_type
, mem
);
1402 checkGLcall("glGetTexImage");
1405 if (surface
->flags
& SFLAG_NONPOW2
)
1407 const BYTE
*src_data
;
1411 * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
1412 * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
1413 * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
1415 * We're doing this...
1417 * instead of boxing the texture :
1418 * |<-texture width ->| -->pow2width| /\
1419 * |111111111111111111| | |
1420 * |222 Texture 222222| boxed empty | texture height
1421 * |3333 Data 33333333| | |
1422 * |444444444444444444| | \/
1423 * ----------------------------------- |
1424 * | boxed empty | boxed empty | pow2height
1426 * -----------------------------------
1429 * we're repacking the data to the expected texture width
1431 * |<-texture width ->| -->pow2width| /\
1432 * |111111111111111111222222222222222| |
1433 * |222333333333333333333444444444444| texture height
1437 * | empty | pow2height
1439 * -----------------------------------
1443 * |<-texture width ->| /\
1444 * |111111111111111111|
1445 * |222222222222222222|texture height
1446 * |333333333333333333|
1447 * |444444444444444444| \/
1448 * --------------------
1450 * This also means that any references to surface memory should work with the data as if it were a
1451 * standard texture with a non-power2 width instead of a texture boxed up to be a power2 texture.
1453 * internally the texture is still stored in a boxed format so any references to textureName will
1454 * get a boxed texture with width pow2width and not a texture of width resource.width.
1456 * Performance should not be an issue, because applications normally do not lock the surfaces when
1457 * rendering. If an app does, the SFLAG_DYNLOCK flag will kick in and the memory copy won't be released,
1458 * and doesn't have to be re-read. */
1460 dst_data
= data
.addr
;
1461 TRACE("(%p) : Repacking the surface data from pitch %d to pitch %d\n", surface
, src_pitch
, dst_pitch
);
1462 for (y
= 0; y
< surface
->resource
.height
; ++y
)
1464 memcpy(dst_data
, src_data
, dst_pitch
);
1465 src_data
+= src_pitch
;
1466 dst_data
+= dst_pitch
;
1469 HeapFree(GetProcessHeap(), 0, mem
);
1474 /* This call just uploads data, the caller is responsible for binding the
1475 * correct texture. */
1476 /* Context activation is done by the caller. */
1477 static void surface_upload_data(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
,
1478 const struct wined3d_format
*format
, const RECT
*src_rect
, UINT src_pitch
, const POINT
*dst_point
,
1479 BOOL srgb
, const struct wined3d_bo_address
*data
)
1481 UINT update_w
= src_rect
->right
- src_rect
->left
;
1482 UINT update_h
= src_rect
->bottom
- src_rect
->top
;
1484 TRACE("surface %p, gl_info %p, format %s, src_rect %s, src_pitch %u, dst_point %s, srgb %#x, data {%#x:%p}.\n",
1485 surface
, gl_info
, debug_d3dformat(format
->id
), wine_dbgstr_rect(src_rect
), src_pitch
,
1486 wine_dbgstr_point(dst_point
), srgb
, data
->buffer_object
, data
->addr
);
1488 if (surface
->resource
.map_count
)
1490 WARN("Uploading a surface that is currently mapped, setting SFLAG_PIN_SYSMEM.\n");
1491 surface
->flags
|= SFLAG_PIN_SYSMEM
;
1494 if (format
->flags
& WINED3DFMT_FLAG_HEIGHT_SCALE
)
1496 update_h
*= format
->height_scale
.numerator
;
1497 update_h
/= format
->height_scale
.denominator
;
1500 if (data
->buffer_object
)
1502 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, data
->buffer_object
));
1503 checkGLcall("glBindBufferARB");
1506 if (format
->flags
& WINED3DFMT_FLAG_COMPRESSED
)
1508 UINT row_length
= wined3d_format_calculate_size(format
, 1, update_w
, 1, 1);
1509 UINT row_count
= (update_h
+ format
->block_height
- 1) / format
->block_height
;
1510 const BYTE
*addr
= data
->addr
;
1513 addr
+= (src_rect
->top
/ format
->block_height
) * src_pitch
;
1514 addr
+= (src_rect
->left
/ format
->block_width
) * format
->block_byte_count
;
1517 internal
= format
->glGammaInternal
;
1518 else if (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
1519 && wined3d_resource_is_offscreen(&surface
->container
->resource
))
1520 internal
= format
->rtInternal
;
1522 internal
= format
->glInternal
;
1524 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
1525 "format %#x, image_size %#x, addr %p.\n", surface
->texture_target
, surface
->texture_level
,
1526 dst_point
->x
, dst_point
->y
, update_w
, update_h
, internal
, row_count
* row_length
, addr
);
1528 if (row_length
== src_pitch
)
1530 GL_EXTCALL(glCompressedTexSubImage2DARB(surface
->texture_target
, surface
->texture_level
,
1531 dst_point
->x
, dst_point
->y
, update_w
, update_h
, internal
, row_count
* row_length
, addr
));
1537 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
1538 * can't use the unpack row length like below. */
1539 for (row
= 0, y
= dst_point
->y
; row
< row_count
; ++row
)
1541 GL_EXTCALL(glCompressedTexSubImage2DARB(surface
->texture_target
, surface
->texture_level
,
1542 dst_point
->x
, y
, update_w
, format
->block_height
, internal
, row_length
, addr
));
1543 y
+= format
->block_height
;
1547 checkGLcall("glCompressedTexSubImage2DARB");
1551 const BYTE
*addr
= data
->addr
;
1553 addr
+= src_rect
->top
* src_pitch
;
1554 addr
+= src_rect
->left
* format
->byte_count
;
1556 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, addr %p.\n",
1557 surface
->texture_target
, surface
->texture_level
, dst_point
->x
, dst_point
->y
,
1558 update_w
, update_h
, format
->glFormat
, format
->glType
, addr
);
1560 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_UNPACK_ROW_LENGTH
, src_pitch
/ format
->byte_count
);
1561 gl_info
->gl_ops
.gl
.p_glTexSubImage2D(surface
->texture_target
, surface
->texture_level
,
1562 dst_point
->x
, dst_point
->y
, update_w
, update_h
, format
->glFormat
, format
->glType
, addr
);
1563 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_UNPACK_ROW_LENGTH
, 0);
1564 checkGLcall("glTexSubImage2D");
1567 if (data
->buffer_object
)
1569 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
1570 checkGLcall("glBindBufferARB");
1573 if (wined3d_settings
.strict_draw_ordering
)
1574 gl_info
->gl_ops
.gl
.p_glFlush();
1576 if (gl_info
->quirks
& WINED3D_QUIRK_FBO_TEX_UPDATE
)
1578 struct wined3d_device
*device
= surface
->resource
.device
;
1581 for (i
= 0; i
< device
->context_count
; ++i
)
1583 context_surface_update(device
->contexts
[i
], surface
);
1588 static void d3dfmt_get_conv(const struct wined3d_texture
*texture
, BOOL need_alpha_ck
,
1589 struct wined3d_format
*format
, enum wined3d_conversion_type
*conversion_type
)
1591 BOOL colorkey_active
= need_alpha_ck
&& (texture
->color_key_flags
& WINEDDSD_CKSRCBLT
);
1592 const struct wined3d_device
*device
= texture
->resource
.device
;
1593 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
1598 enum wined3d_format_id src_format
;
1599 enum wined3d_conversion_type conversion_type
;
1603 unsigned int conv_byte_count
;
1607 {WINED3DFMT_B5G6R5_UNORM
, WINED3D_CT_CK_B5G6R5
, GL_RGB5_A1
, GL_BGRA
, GL_UNSIGNED_SHORT_1_5_5_5_REV
, 2},
1608 {WINED3DFMT_B5G5R5X1_UNORM
, WINED3D_CT_CK_B5G5R5X1
, GL_RGB5_A1
, GL_BGRA
, GL_UNSIGNED_SHORT_1_5_5_5_REV
, 2},
1609 {WINED3DFMT_B8G8R8_UNORM
, WINED3D_CT_CK_B8G8R8
, GL_RGBA8
, GL_BGRA
, GL_UNSIGNED_INT_8_8_8_8_REV
, 4},
1610 {WINED3DFMT_B8G8R8X8_UNORM
, WINED3D_CT_CK_B8G8R8X8
, GL_RGBA8
, GL_BGRA
, GL_UNSIGNED_INT_8_8_8_8_REV
, 4},
1611 {WINED3DFMT_B8G8R8A8_UNORM
, WINED3D_CT_CK_B8G8R8A8
, GL_RGBA8
, GL_BGRA
, GL_UNSIGNED_INT_8_8_8_8_REV
, 4},
1614 *format
= *texture
->resource
.format
;
1615 *conversion_type
= WINED3D_CT_NONE
;
1617 if (colorkey_active
)
1619 for (i
= 0; i
< sizeof(color_key_info
) / sizeof(*color_key_info
); ++i
)
1621 if (color_key_info
[i
].src_format
!= texture
->resource
.format
->id
)
1624 *conversion_type
= color_key_info
[i
].conversion_type
;
1625 format
->glInternal
= color_key_info
[i
].gl_internal
;
1626 format
->glFormat
= color_key_info
[i
].gl_format
;
1627 format
->glType
= color_key_info
[i
].gl_type
;
1628 format
->conv_byte_count
= color_key_info
[i
].conv_byte_count
;
1633 if (texture
->resource
.format
->id
== WINED3DFMT_P8_UINT
)
1635 /* FIXME: This should check if the blitter backend can do P8
1636 * conversion, instead of checking for ARB_fragment_program. */
1637 if (!((gl_info
->supported
[ARB_FRAGMENT_PROGRAM
] && texture
->swapchain
1638 && texture
== texture
->swapchain
->front_buffer
)) || colorkey_active
)
1640 *conversion_type
= WINED3D_CT_P8
;
1641 format
->glInternal
= GL_RGBA8
;
1642 format
->glFormat
= GL_BGRA
;
1643 format
->glType
= GL_UNSIGNED_INT_8_8_8_8_REV
;
1644 format
->conv_byte_count
= 4;
1647 else if (texture
->resource
.format
->id
== WINED3DFMT_B2G3R3_UNORM
&& colorkey_active
)
1649 /* This texture format will never be used... So do not care about
1650 * color-keying up until the point in time it will be needed. */
1651 FIXME("Color-keying not supported with WINED3DFMT_B2G3R3_UNORM.\n");
1654 if (*conversion_type
!= WINED3D_CT_NONE
)
1656 format
->rtInternal
= format
->glInternal
;
1657 format
->glGammaInternal
= format
->glInternal
;
1661 static BOOL
surface_check_block_align(struct wined3d_surface
*surface
, const RECT
*rect
)
1663 UINT width_mask
, height_mask
;
1665 if (!rect
->left
&& !rect
->top
1666 && rect
->right
== surface
->resource
.width
1667 && rect
->bottom
== surface
->resource
.height
)
1670 /* This assumes power of two block sizes, but NPOT block sizes would be
1672 width_mask
= surface
->resource
.format
->block_width
- 1;
1673 height_mask
= surface
->resource
.format
->block_height
- 1;
1675 if (!(rect
->left
& width_mask
) && !(rect
->top
& height_mask
)
1676 && !(rect
->right
& width_mask
) && !(rect
->bottom
& height_mask
))
1682 HRESULT
surface_upload_from_surface(struct wined3d_surface
*dst_surface
, const POINT
*dst_point
,
1683 struct wined3d_surface
*src_surface
, const RECT
*src_rect
)
1685 const struct wined3d_format
*src_format
;
1686 const struct wined3d_format
*dst_format
;
1687 const struct wined3d_gl_info
*gl_info
;
1688 enum wined3d_conversion_type convert
;
1689 struct wined3d_context
*context
;
1690 struct wined3d_bo_address data
;
1691 struct wined3d_format format
;
1692 UINT update_w
, update_h
;
1698 TRACE("dst_surface %p, dst_point %s, src_surface %p, src_rect %s.\n",
1699 dst_surface
, wine_dbgstr_point(dst_point
),
1700 src_surface
, wine_dbgstr_rect(src_rect
));
1702 src_format
= src_surface
->resource
.format
;
1703 dst_format
= dst_surface
->resource
.format
;
1705 if (src_format
->id
!= dst_format
->id
)
1707 WARN("Source and destination surfaces should have the same format.\n");
1708 return WINED3DERR_INVALIDCALL
;
1717 else if (dst_point
->x
< 0 || dst_point
->y
< 0)
1719 WARN("Invalid destination point.\n");
1720 return WINED3DERR_INVALIDCALL
;
1727 r
.right
= src_surface
->resource
.width
;
1728 r
.bottom
= src_surface
->resource
.height
;
1731 else if (src_rect
->left
< 0 || src_rect
->left
>= src_rect
->right
1732 || src_rect
->top
< 0 || src_rect
->top
>= src_rect
->bottom
)
1734 WARN("Invalid source rectangle.\n");
1735 return WINED3DERR_INVALIDCALL
;
1738 dst_w
= dst_surface
->resource
.width
;
1739 dst_h
= dst_surface
->resource
.height
;
1741 update_w
= src_rect
->right
- src_rect
->left
;
1742 update_h
= src_rect
->bottom
- src_rect
->top
;
1744 if (update_w
> dst_w
|| dst_point
->x
> dst_w
- update_w
1745 || update_h
> dst_h
|| dst_point
->y
> dst_h
- update_h
)
1747 WARN("Destination out of bounds.\n");
1748 return WINED3DERR_INVALIDCALL
;
1751 if ((src_format
->flags
& WINED3DFMT_FLAG_BLOCKS
) && !surface_check_block_align(src_surface
, src_rect
))
1753 WARN("Source rectangle not block-aligned.\n");
1754 return WINED3DERR_INVALIDCALL
;
1757 SetRect(&dst_rect
, dst_point
->x
, dst_point
->y
, dst_point
->x
+ update_w
, dst_point
->y
+ update_h
);
1758 if ((dst_format
->flags
& WINED3DFMT_FLAG_BLOCKS
) && !surface_check_block_align(dst_surface
, &dst_rect
))
1760 WARN("Destination rectangle not block-aligned.\n");
1761 return WINED3DERR_INVALIDCALL
;
1764 /* Use wined3d_surface_blt() instead of uploading directly if we need conversion. */
1765 d3dfmt_get_conv(dst_surface
->container
, FALSE
, &format
, &convert
);
1766 if (convert
!= WINED3D_CT_NONE
|| format
.convert
)
1767 return wined3d_surface_blt(dst_surface
, &dst_rect
, src_surface
, src_rect
, 0, NULL
, WINED3D_TEXF_POINT
);
1769 context
= context_acquire(dst_surface
->resource
.device
, NULL
);
1770 gl_info
= context
->gl_info
;
1772 /* Only load the surface for partial updates. For newly allocated texture
1773 * the texture wouldn't be the current location, and we'd upload zeroes
1774 * just to overwrite them again. */
1775 if (update_w
== dst_w
&& update_h
== dst_h
)
1776 surface_prepare_texture(dst_surface
, context
, FALSE
);
1778 surface_load_location(dst_surface
, WINED3D_LOCATION_TEXTURE_RGB
);
1779 wined3d_texture_bind(dst_surface
->container
, context
, FALSE
);
1781 surface_get_memory(src_surface
, &data
, src_surface
->locations
);
1782 src_pitch
= wined3d_surface_get_pitch(src_surface
);
1784 surface_upload_data(dst_surface
, gl_info
, src_format
, src_rect
, src_pitch
, dst_point
, FALSE
, &data
);
1786 context_invalidate_active_texture(context
);
1788 context_release(context
);
1790 surface_validate_location(dst_surface
, WINED3D_LOCATION_TEXTURE_RGB
);
1791 surface_invalidate_location(dst_surface
, ~WINED3D_LOCATION_TEXTURE_RGB
);
1796 /* This call just allocates the texture, the caller is responsible for binding
1797 * the correct texture. */
1798 /* Context activation is done by the caller. */
1799 static void surface_allocate_surface(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
,
1800 const struct wined3d_format
*format
, BOOL srgb
)
1802 BOOL disable_client_storage
= FALSE
;
1803 GLsizei width
= surface
->pow2Width
;
1804 GLsizei height
= surface
->pow2Height
;
1805 const BYTE
*mem
= NULL
;
1809 internal
= format
->glGammaInternal
;
1810 else if (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
1811 && wined3d_resource_is_offscreen(&surface
->container
->resource
))
1812 internal
= format
->rtInternal
;
1814 internal
= format
->glInternal
;
1817 FIXME("No GL internal format for format %s.\n", debug_d3dformat(format
->id
));
1819 if (format
->flags
& WINED3DFMT_FLAG_HEIGHT_SCALE
)
1821 height
*= format
->height_scale
.numerator
;
1822 height
/= format
->height_scale
.denominator
;
1825 TRACE("(%p) : Creating surface (target %#x) level %d, d3d format %s, internal format %#x, width %d, height %d, gl format %#x, gl type=%#x\n",
1826 surface
, surface
->texture_target
, surface
->texture_level
, debug_d3dformat(format
->id
),
1827 internal
, width
, height
, format
->glFormat
, format
->glType
);
1829 if (gl_info
->supported
[APPLE_CLIENT_STORAGE
])
1831 if (surface
->flags
& (SFLAG_NONPOW2
| SFLAG_DIBSECTION
| SFLAG_CONVERTED
)
1832 || !surface
->resource
.heap_memory
)
1834 /* In some cases we want to disable client storage.
1835 * SFLAG_NONPOW2 has a bigger opengl texture than the client memory, and different pitches
1836 * SFLAG_DIBSECTION: Dibsections may have read / write protections on the memory. Avoid issues...
1837 * SFLAG_CONVERTED: The conversion destination memory is freed after loading the surface
1838 * heap_memory == NULL: Not defined in the extension. Seems to disable client storage effectively
1840 surface
->flags
&= ~SFLAG_CLIENT
;
1844 surface
->flags
|= SFLAG_CLIENT
;
1845 mem
= surface
->resource
.heap_memory
;
1847 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
1848 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1849 disable_client_storage
= TRUE
;
1853 if (format
->flags
& WINED3DFMT_FLAG_COMPRESSED
&& mem
)
1855 GL_EXTCALL(glCompressedTexImage2DARB(surface
->texture_target
, surface
->texture_level
,
1856 internal
, width
, height
, 0, surface
->resource
.size
, mem
));
1857 checkGLcall("glCompressedTexImage2DARB");
1861 gl_info
->gl_ops
.gl
.p_glTexImage2D(surface
->texture_target
, surface
->texture_level
,
1862 internal
, width
, height
, 0, format
->glFormat
, format
->glType
, mem
);
1863 checkGLcall("glTexImage2D");
1866 if (disable_client_storage
)
1868 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
1869 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1873 /* In D3D the depth stencil dimensions have to be greater than or equal to the
1874 * render target dimensions. With FBOs, the dimensions have to be an exact match. */
1875 /* TODO: We should synchronize the renderbuffer's content with the texture's content. */
1876 /* Context activation is done by the caller. */
1877 void surface_set_compatible_renderbuffer(struct wined3d_surface
*surface
, const struct wined3d_surface
*rt
)
1879 const struct wined3d_gl_info
*gl_info
= &surface
->resource
.device
->adapter
->gl_info
;
1880 struct wined3d_renderbuffer_entry
*entry
;
1881 GLuint renderbuffer
= 0;
1882 unsigned int src_width
, src_height
;
1883 unsigned int width
, height
;
1885 if (rt
&& rt
->resource
.format
->id
!= WINED3DFMT_NULL
)
1887 width
= rt
->pow2Width
;
1888 height
= rt
->pow2Height
;
1892 width
= surface
->pow2Width
;
1893 height
= surface
->pow2Height
;
1896 src_width
= surface
->pow2Width
;
1897 src_height
= surface
->pow2Height
;
1899 /* A depth stencil smaller than the render target is not valid */
1900 if (width
> src_width
|| height
> src_height
) return;
1902 /* Remove any renderbuffer set if the sizes match */
1903 if (gl_info
->supported
[ARB_FRAMEBUFFER_OBJECT
]
1904 || (width
== src_width
&& height
== src_height
))
1906 surface
->current_renderbuffer
= NULL
;
1910 /* Look if we've already got a renderbuffer of the correct dimensions */
1911 LIST_FOR_EACH_ENTRY(entry
, &surface
->renderbuffers
, struct wined3d_renderbuffer_entry
, entry
)
1913 if (entry
->width
== width
&& entry
->height
== height
)
1915 renderbuffer
= entry
->id
;
1916 surface
->current_renderbuffer
= entry
;
1923 gl_info
->fbo_ops
.glGenRenderbuffers(1, &renderbuffer
);
1924 gl_info
->fbo_ops
.glBindRenderbuffer(GL_RENDERBUFFER
, renderbuffer
);
1925 gl_info
->fbo_ops
.glRenderbufferStorage(GL_RENDERBUFFER
,
1926 surface
->resource
.format
->glInternal
, width
, height
);
1928 entry
= HeapAlloc(GetProcessHeap(), 0, sizeof(*entry
));
1929 entry
->width
= width
;
1930 entry
->height
= height
;
1931 entry
->id
= renderbuffer
;
1932 list_add_head(&surface
->renderbuffers
, &entry
->entry
);
1934 surface
->current_renderbuffer
= entry
;
1937 checkGLcall("set_compatible_renderbuffer");
1940 GLenum
surface_get_gl_buffer(const struct wined3d_surface
*surface
)
1942 const struct wined3d_swapchain
*swapchain
= surface
->container
->swapchain
;
1944 TRACE("surface %p.\n", surface
);
1948 ERR("Surface %p is not on a swapchain.\n", surface
);
1952 if (swapchain
->back_buffers
&& swapchain
->back_buffers
[0] == surface
->container
)
1954 if (swapchain
->render_to_fbo
)
1956 TRACE("Returning GL_COLOR_ATTACHMENT0\n");
1957 return GL_COLOR_ATTACHMENT0
;
1959 TRACE("Returning GL_BACK\n");
1962 else if (surface
->container
== swapchain
->front_buffer
)
1964 TRACE("Returning GL_FRONT\n");
1968 FIXME("Higher back buffer, returning GL_BACK\n");
1972 void surface_load(struct wined3d_surface
*surface
, BOOL srgb
)
1974 DWORD location
= srgb
? WINED3D_LOCATION_TEXTURE_SRGB
: WINED3D_LOCATION_TEXTURE_RGB
;
1977 TRACE("surface %p, srgb %#x.\n", surface
, srgb
);
1979 if (surface
->resource
.pool
== WINED3D_POOL_SCRATCH
)
1980 ERR("Not supported on scratch surfaces.\n");
1982 ck_changed
= !(surface
->flags
& SFLAG_GLCKEY
) != !(surface
->container
->color_key_flags
& WINEDDSD_CKSRCBLT
);
1984 /* Reload if either the texture and sysmem have different ideas about the
1985 * color key, or the actual key values changed. */
1986 if (ck_changed
|| ((surface
->container
->color_key_flags
& WINEDDSD_CKSRCBLT
)
1987 && (surface
->gl_color_key
.color_space_low_value
1988 != surface
->container
->src_blt_color_key
.color_space_low_value
1989 || surface
->gl_color_key
.color_space_high_value
1990 != surface
->container
->src_blt_color_key
.color_space_high_value
)))
1992 TRACE("Reloading because of color keying\n");
1993 /* To perform the color key conversion we need a sysmem copy of
1994 * the surface. Make sure we have it. */
1996 surface_prepare_map_memory(surface
);
1997 surface_load_location(surface
, surface
->resource
.map_binding
);
1998 surface_invalidate_location(surface
, ~surface
->resource
.map_binding
);
1999 /* Switching color keying on / off may change the internal format. */
2001 surface_force_reload(surface
);
2003 else if (!(surface
->locations
& location
))
2005 TRACE("Reloading because surface is dirty.\n");
2009 TRACE("surface is already in texture\n");
2013 surface_load_location(surface
, location
);
2014 surface_evict_sysmem(surface
);
2017 /* See also float_16_to_32() in wined3d_private.h */
2018 static inline unsigned short float_32_to_16(const float *in
)
2021 float tmp
= fabsf(*in
);
2022 unsigned int mantissa
;
2025 /* Deal with special numbers */
2031 return (*in
< 0.0f
? 0xfc00 : 0x7c00);
2033 if (tmp
< powf(2, 10))
2039 } while (tmp
< powf(2, 10));
2041 else if (tmp
>= powf(2, 11))
2047 } while (tmp
>= powf(2, 11));
2050 mantissa
= (unsigned int)tmp
;
2051 if (tmp
- mantissa
>= 0.5f
)
2052 ++mantissa
; /* Round to nearest, away from zero. */
2054 exp
+= 10; /* Normalize the mantissa. */
2055 exp
+= 15; /* Exponent is encoded with excess 15. */
2057 if (exp
> 30) /* too big */
2059 ret
= 0x7c00; /* INF */
2063 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers. */
2066 mantissa
= mantissa
>> 1;
2069 ret
= mantissa
& 0x3ff;
2073 ret
= (exp
<< 10) | (mantissa
& 0x3ff);
2076 ret
|= ((*in
< 0.0f
? 1 : 0) << 15); /* Add the sign */
2080 ULONG CDECL
wined3d_surface_incref(struct wined3d_surface
*surface
)
2082 TRACE("surface %p, container %p.\n", surface
, surface
->container
);
2084 return wined3d_texture_incref(surface
->container
);
2087 ULONG CDECL
wined3d_surface_decref(struct wined3d_surface
*surface
)
2089 TRACE("surface %p, container %p.\n", surface
, surface
->container
);
2091 return wined3d_texture_decref(surface
->container
);
2094 void CDECL
wined3d_surface_preload(struct wined3d_surface
*surface
)
2096 TRACE("surface %p.\n", surface
);
2098 if (!surface
->resource
.device
->d3d_initialized
)
2100 ERR("D3D not initialized.\n");
2104 wined3d_texture_preload(surface
->container
);
2107 void * CDECL
wined3d_surface_get_parent(const struct wined3d_surface
*surface
)
2109 TRACE("surface %p.\n", surface
);
2111 return surface
->resource
.parent
;
2114 struct wined3d_resource
* CDECL
wined3d_surface_get_resource(struct wined3d_surface
*surface
)
2116 TRACE("surface %p.\n", surface
);
2118 return &surface
->resource
;
2121 HRESULT CDECL
wined3d_surface_get_blt_status(const struct wined3d_surface
*surface
, DWORD flags
)
2123 TRACE("surface %p, flags %#x.\n", surface
, flags
);
2127 case WINEDDGBS_CANBLT
:
2128 case WINEDDGBS_ISBLTDONE
:
2132 return WINED3DERR_INVALIDCALL
;
2136 HRESULT CDECL
wined3d_surface_get_flip_status(const struct wined3d_surface
*surface
, DWORD flags
)
2138 TRACE("surface %p, flags %#x.\n", surface
, flags
);
2140 /* XXX: DDERR_INVALIDSURFACETYPE */
2144 case WINEDDGFS_CANFLIP
:
2145 case WINEDDGFS_ISFLIPDONE
:
2149 return WINED3DERR_INVALIDCALL
;
2153 HRESULT CDECL
wined3d_surface_is_lost(const struct wined3d_surface
*surface
)
2155 TRACE("surface %p.\n", surface
);
2157 /* D3D8 and 9 loose full devices, ddraw only surfaces. */
2158 return surface
->flags
& SFLAG_LOST
? WINED3DERR_DEVICELOST
: WINED3D_OK
;
2161 HRESULT CDECL
wined3d_surface_restore(struct wined3d_surface
*surface
)
2163 TRACE("surface %p.\n", surface
);
2165 surface
->flags
&= ~SFLAG_LOST
;
2169 DWORD CDECL
wined3d_surface_get_pitch(const struct wined3d_surface
*surface
)
2171 unsigned int alignment
;
2174 TRACE("surface %p.\n", surface
);
2177 return surface
->pitch
;
2179 alignment
= surface
->resource
.device
->surface_alignment
;
2180 pitch
= wined3d_format_calculate_pitch(surface
->resource
.format
, surface
->resource
.width
);
2181 pitch
= (pitch
+ alignment
- 1) & ~(alignment
- 1);
2183 TRACE("Returning %u.\n", pitch
);
2188 HRESULT CDECL
wined3d_surface_set_overlay_position(struct wined3d_surface
*surface
, LONG x
, LONG y
)
2192 TRACE("surface %p, x %d, y %d.\n", surface
, x
, y
);
2194 if (!(surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
2196 WARN("Not an overlay surface.\n");
2197 return WINEDDERR_NOTAOVERLAYSURFACE
;
2200 w
= surface
->overlay_destrect
.right
- surface
->overlay_destrect
.left
;
2201 h
= surface
->overlay_destrect
.bottom
- surface
->overlay_destrect
.top
;
2202 surface
->overlay_destrect
.left
= x
;
2203 surface
->overlay_destrect
.top
= y
;
2204 surface
->overlay_destrect
.right
= x
+ w
;
2205 surface
->overlay_destrect
.bottom
= y
+ h
;
2210 HRESULT CDECL
wined3d_surface_get_overlay_position(const struct wined3d_surface
*surface
, LONG
*x
, LONG
*y
)
2212 TRACE("surface %p, x %p, y %p.\n", surface
, x
, y
);
2214 if (!(surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
2216 TRACE("Not an overlay surface.\n");
2217 return WINEDDERR_NOTAOVERLAYSURFACE
;
2220 if (!surface
->overlay_dest
)
2222 TRACE("Overlay not visible.\n");
2225 return WINEDDERR_OVERLAYNOTVISIBLE
;
2228 *x
= surface
->overlay_destrect
.left
;
2229 *y
= surface
->overlay_destrect
.top
;
2231 TRACE("Returning position %d, %d.\n", *x
, *y
);
2236 HRESULT CDECL
wined3d_surface_update_overlay_z_order(struct wined3d_surface
*surface
,
2237 DWORD flags
, struct wined3d_surface
*ref
)
2239 FIXME("surface %p, flags %#x, ref %p stub!\n", surface
, flags
, ref
);
2241 if (!(surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
2243 TRACE("Not an overlay surface.\n");
2244 return WINEDDERR_NOTAOVERLAYSURFACE
;
2250 HRESULT CDECL
wined3d_surface_update_overlay(struct wined3d_surface
*surface
, const RECT
*src_rect
,
2251 struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
, DWORD flags
, const WINEDDOVERLAYFX
*fx
)
2253 TRACE("surface %p, src_rect %s, dst_surface %p, dst_rect %s, flags %#x, fx %p.\n",
2254 surface
, wine_dbgstr_rect(src_rect
), dst_surface
, wine_dbgstr_rect(dst_rect
), flags
, fx
);
2256 if (!(surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
2258 WARN("Not an overlay surface.\n");
2259 return WINEDDERR_NOTAOVERLAYSURFACE
;
2261 else if (!dst_surface
)
2263 WARN("Dest surface is NULL.\n");
2264 return WINED3DERR_INVALIDCALL
;
2269 surface
->overlay_srcrect
= *src_rect
;
2273 surface
->overlay_srcrect
.left
= 0;
2274 surface
->overlay_srcrect
.top
= 0;
2275 surface
->overlay_srcrect
.right
= surface
->resource
.width
;
2276 surface
->overlay_srcrect
.bottom
= surface
->resource
.height
;
2281 surface
->overlay_destrect
= *dst_rect
;
2285 surface
->overlay_destrect
.left
= 0;
2286 surface
->overlay_destrect
.top
= 0;
2287 surface
->overlay_destrect
.right
= dst_surface
? dst_surface
->resource
.width
: 0;
2288 surface
->overlay_destrect
.bottom
= dst_surface
? dst_surface
->resource
.height
: 0;
2291 if (surface
->overlay_dest
&& (surface
->overlay_dest
!= dst_surface
|| flags
& WINEDDOVER_HIDE
))
2293 surface
->overlay_dest
= NULL
;
2294 list_remove(&surface
->overlay_entry
);
2297 if (flags
& WINEDDOVER_SHOW
)
2299 if (surface
->overlay_dest
!= dst_surface
)
2301 surface
->overlay_dest
= dst_surface
;
2302 list_add_tail(&dst_surface
->overlays
, &surface
->overlay_entry
);
2305 else if (flags
& WINEDDOVER_HIDE
)
2307 /* tests show that the rectangles are erased on hide */
2308 surface
->overlay_srcrect
.left
= 0; surface
->overlay_srcrect
.top
= 0;
2309 surface
->overlay_srcrect
.right
= 0; surface
->overlay_srcrect
.bottom
= 0;
2310 surface
->overlay_destrect
.left
= 0; surface
->overlay_destrect
.top
= 0;
2311 surface
->overlay_destrect
.right
= 0; surface
->overlay_destrect
.bottom
= 0;
2312 surface
->overlay_dest
= NULL
;
2318 HRESULT
wined3d_surface_update_desc(struct wined3d_surface
*surface
,
2319 const struct wined3d_gl_info
*gl_info
, void *mem
, unsigned int pitch
)
2321 struct wined3d_resource
*texture_resource
= &surface
->container
->resource
;
2322 unsigned int width
, height
;
2323 BOOL create_dib
= FALSE
;
2324 DWORD valid_location
= 0;
2327 if (surface
->flags
& SFLAG_DIBSECTION
)
2329 DeleteDC(surface
->hDC
);
2330 DeleteObject(surface
->dib
.DIBsection
);
2331 surface
->dib
.bitmap_data
= NULL
;
2332 surface
->flags
&= ~SFLAG_DIBSECTION
;
2336 surface
->locations
= 0;
2337 wined3d_resource_free_sysmem(&surface
->resource
);
2339 width
= texture_resource
->width
;
2340 height
= texture_resource
->height
;
2341 surface
->resource
.width
= width
;
2342 surface
->resource
.height
= height
;
2343 if (gl_info
->supported
[ARB_TEXTURE_NON_POWER_OF_TWO
] || gl_info
->supported
[ARB_TEXTURE_RECTANGLE
]
2344 || gl_info
->supported
[WINED3D_GL_NORMALIZED_TEXRECT
])
2346 surface
->pow2Width
= width
;
2347 surface
->pow2Height
= height
;
2351 surface
->pow2Width
= surface
->pow2Height
= 1;
2352 while (surface
->pow2Width
< width
)
2353 surface
->pow2Width
<<= 1;
2354 while (surface
->pow2Height
< height
)
2355 surface
->pow2Height
<<= 1;
2358 if (surface
->pow2Width
!= width
|| surface
->pow2Height
!= height
)
2359 surface
->flags
|= SFLAG_NONPOW2
;
2361 surface
->flags
&= ~SFLAG_NONPOW2
;
2363 if ((surface
->user_memory
= mem
))
2365 surface
->resource
.map_binding
= WINED3D_LOCATION_USER_MEMORY
;
2366 valid_location
= WINED3D_LOCATION_USER_MEMORY
;
2368 surface
->pitch
= pitch
;
2369 surface
->resource
.format
= texture_resource
->format
;
2370 surface
->resource
.multisample_type
= texture_resource
->multisample_type
;
2371 surface
->resource
.multisample_quality
= texture_resource
->multisample_quality
;
2373 surface
->resource
.size
= height
* surface
->pitch
;
2375 surface
->resource
.size
= wined3d_format_calculate_size(texture_resource
->format
,
2376 texture_resource
->device
->surface_alignment
, width
, height
, 1);
2378 /* The format might be changed to a format that needs conversion.
2379 * If the surface didn't use PBOs previously but could now, don't
2380 * change it - whatever made us not use PBOs might come back, e.g.
2382 if (surface
->resource
.map_binding
== WINED3D_LOCATION_BUFFER
&& !surface_use_pbo(surface
))
2383 surface
->resource
.map_binding
= create_dib
? WINED3D_LOCATION_DIB
: WINED3D_LOCATION_SYSMEM
;
2387 if (FAILED(hr
= surface_create_dib_section(surface
)))
2389 ERR("Failed to create dib section, hr %#x.\n", hr
);
2392 if (!valid_location
)
2393 valid_location
= WINED3D_LOCATION_DIB
;
2396 if (!valid_location
)
2398 surface_prepare_system_memory(surface
);
2399 valid_location
= WINED3D_LOCATION_SYSMEM
;
2402 surface_validate_location(surface
, valid_location
);
2407 static void convert_r32_float_r16_float(const BYTE
*src
, BYTE
*dst
,
2408 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2410 unsigned short *dst_s
;
2414 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
2416 for (y
= 0; y
< h
; ++y
)
2418 src_f
= (const float *)(src
+ y
* pitch_in
);
2419 dst_s
= (unsigned short *) (dst
+ y
* pitch_out
);
2420 for (x
= 0; x
< w
; ++x
)
2422 dst_s
[x
] = float_32_to_16(src_f
+ x
);
2427 static void convert_r5g6b5_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
2428 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2430 static const unsigned char convert_5to8
[] =
2432 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
2433 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
2434 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
2435 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
2437 static const unsigned char convert_6to8
[] =
2439 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
2440 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
2441 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
2442 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
2443 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
2444 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
2445 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
2446 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
2450 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
2452 for (y
= 0; y
< h
; ++y
)
2454 const WORD
*src_line
= (const WORD
*)(src
+ y
* pitch_in
);
2455 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
2456 for (x
= 0; x
< w
; ++x
)
2458 WORD pixel
= src_line
[x
];
2459 dst_line
[x
] = 0xff000000
2460 | convert_5to8
[(pixel
& 0xf800) >> 11] << 16
2461 | convert_6to8
[(pixel
& 0x07e0) >> 5] << 8
2462 | convert_5to8
[(pixel
& 0x001f)];
2467 /* We use this for both B8G8R8A8 -> B8G8R8X8 and B8G8R8X8 -> B8G8R8A8, since
2468 * in both cases we're just setting the X / Alpha channel to 0xff. */
2469 static void convert_a8r8g8b8_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
2470 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2474 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
2476 for (y
= 0; y
< h
; ++y
)
2478 const DWORD
*src_line
= (const DWORD
*)(src
+ y
* pitch_in
);
2479 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
2481 for (x
= 0; x
< w
; ++x
)
2483 dst_line
[x
] = 0xff000000 | (src_line
[x
] & 0xffffff);
2488 static inline BYTE
cliptobyte(int x
)
2490 return (BYTE
)((x
< 0) ? 0 : ((x
> 255) ? 255 : x
));
2493 static void convert_yuy2_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
2494 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2496 int c2
, d
, e
, r2
= 0, g2
= 0, b2
= 0;
2499 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
2501 for (y
= 0; y
< h
; ++y
)
2503 const BYTE
*src_line
= src
+ y
* pitch_in
;
2504 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
2505 for (x
= 0; x
< w
; ++x
)
2507 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
2508 * C = Y - 16; D = U - 128; E = V - 128;
2509 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
2510 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
2511 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
2512 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
2513 * U and V are shared between the pixels. */
2514 if (!(x
& 1)) /* For every even pixel, read new U and V. */
2516 d
= (int) src_line
[1] - 128;
2517 e
= (int) src_line
[3] - 128;
2519 g2
= - 100 * d
- 208 * e
+ 128;
2522 c2
= 298 * ((int) src_line
[0] - 16);
2523 dst_line
[x
] = 0xff000000
2524 | cliptobyte((c2
+ r2
) >> 8) << 16 /* red */
2525 | cliptobyte((c2
+ g2
) >> 8) << 8 /* green */
2526 | cliptobyte((c2
+ b2
) >> 8); /* blue */
2527 /* Scale RGB values to 0..255 range,
2528 * then clip them if still not in range (may be negative),
2529 * then shift them within DWORD if necessary. */
2535 static void convert_yuy2_r5g6b5(const BYTE
*src
, BYTE
*dst
,
2536 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2539 int c2
, d
, e
, r2
= 0, g2
= 0, b2
= 0;
2541 TRACE("Converting %ux%u pixels, pitches %u %u\n", w
, h
, pitch_in
, pitch_out
);
2543 for (y
= 0; y
< h
; ++y
)
2545 const BYTE
*src_line
= src
+ y
* pitch_in
;
2546 WORD
*dst_line
= (WORD
*)(dst
+ y
* pitch_out
);
2547 for (x
= 0; x
< w
; ++x
)
2549 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
2550 * C = Y - 16; D = U - 128; E = V - 128;
2551 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
2552 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
2553 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
2554 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
2555 * U and V are shared between the pixels. */
2556 if (!(x
& 1)) /* For every even pixel, read new U and V. */
2558 d
= (int) src_line
[1] - 128;
2559 e
= (int) src_line
[3] - 128;
2561 g2
= - 100 * d
- 208 * e
+ 128;
2564 c2
= 298 * ((int) src_line
[0] - 16);
2565 dst_line
[x
] = (cliptobyte((c2
+ r2
) >> 8) >> 3) << 11 /* red */
2566 | (cliptobyte((c2
+ g2
) >> 8) >> 2) << 5 /* green */
2567 | (cliptobyte((c2
+ b2
) >> 8) >> 3); /* blue */
2568 /* Scale RGB values to 0..255 range,
2569 * then clip them if still not in range (may be negative),
2570 * then shift them within DWORD if necessary. */
2576 struct d3dfmt_converter_desc
2578 enum wined3d_format_id from
, to
;
2579 void (*convert
)(const BYTE
*src
, BYTE
*dst
, DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
);
2582 static const struct d3dfmt_converter_desc converters
[] =
2584 {WINED3DFMT_R32_FLOAT
, WINED3DFMT_R16_FLOAT
, convert_r32_float_r16_float
},
2585 {WINED3DFMT_B5G6R5_UNORM
, WINED3DFMT_B8G8R8X8_UNORM
, convert_r5g6b5_x8r8g8b8
},
2586 {WINED3DFMT_B8G8R8A8_UNORM
, WINED3DFMT_B8G8R8X8_UNORM
, convert_a8r8g8b8_x8r8g8b8
},
2587 {WINED3DFMT_B8G8R8X8_UNORM
, WINED3DFMT_B8G8R8A8_UNORM
, convert_a8r8g8b8_x8r8g8b8
},
2588 {WINED3DFMT_YUY2
, WINED3DFMT_B8G8R8X8_UNORM
, convert_yuy2_x8r8g8b8
},
2589 {WINED3DFMT_YUY2
, WINED3DFMT_B5G6R5_UNORM
, convert_yuy2_r5g6b5
},
2592 static inline const struct d3dfmt_converter_desc
*find_converter(enum wined3d_format_id from
,
2593 enum wined3d_format_id to
)
2597 for (i
= 0; i
< (sizeof(converters
) / sizeof(*converters
)); ++i
)
2599 if (converters
[i
].from
== from
&& converters
[i
].to
== to
)
2600 return &converters
[i
];
2606 static struct wined3d_texture
*surface_convert_format(struct wined3d_surface
*source
, enum wined3d_format_id to_fmt
)
2608 struct wined3d_map_desc src_map
, dst_map
;
2609 const struct d3dfmt_converter_desc
*conv
;
2610 struct wined3d_texture
*ret
= NULL
;
2611 struct wined3d_resource_desc desc
;
2612 struct wined3d_surface
*dst
;
2614 conv
= find_converter(source
->resource
.format
->id
, to_fmt
);
2617 FIXME("Cannot find a conversion function from format %s to %s.\n",
2618 debug_d3dformat(source
->resource
.format
->id
), debug_d3dformat(to_fmt
));
2622 /* FIXME: Multisampled conversion? */
2623 wined3d_resource_get_desc(&source
->resource
, &desc
);
2624 desc
.resource_type
= WINED3D_RTYPE_TEXTURE
;
2625 desc
.format
= to_fmt
;
2627 desc
.pool
= WINED3D_POOL_SCRATCH
;
2628 if (FAILED(wined3d_texture_create(source
->resource
.device
, &desc
, 1,
2629 WINED3D_SURFACE_MAPPABLE
| WINED3D_SURFACE_DISCARD
, NULL
, &wined3d_null_parent_ops
, &ret
)))
2631 ERR("Failed to create a destination surface for conversion.\n");
2634 dst
= surface_from_resource(wined3d_texture_get_sub_resource(ret
, 0));
2636 memset(&src_map
, 0, sizeof(src_map
));
2637 memset(&dst_map
, 0, sizeof(dst_map
));
2639 if (FAILED(wined3d_surface_map(source
, &src_map
, NULL
, WINED3D_MAP_READONLY
)))
2641 ERR("Failed to lock the source surface.\n");
2642 wined3d_texture_decref(ret
);
2645 if (FAILED(wined3d_surface_map(dst
, &dst_map
, NULL
, 0)))
2647 ERR("Failed to lock the destination surface.\n");
2648 wined3d_surface_unmap(source
);
2649 wined3d_texture_decref(ret
);
2653 conv
->convert(src_map
.data
, dst_map
.data
, src_map
.row_pitch
, dst_map
.row_pitch
,
2654 source
->resource
.width
, source
->resource
.height
);
2656 wined3d_surface_unmap(dst
);
2657 wined3d_surface_unmap(source
);
2662 static HRESULT
_Blt_ColorFill(BYTE
*buf
, unsigned int width
, unsigned int height
,
2663 unsigned int bpp
, UINT pitch
, DWORD color
)
2670 #define COLORFILL_ROW(type) \
2672 type *d = (type *)buf; \
2673 for (x = 0; x < width; ++x) \
2674 d[x] = (type)color; \
2680 COLORFILL_ROW(BYTE
);
2684 COLORFILL_ROW(WORD
);
2690 for (x
= 0; x
< width
; ++x
, d
+= 3)
2692 d
[0] = (color
) & 0xff;
2693 d
[1] = (color
>> 8) & 0xff;
2694 d
[2] = (color
>> 16) & 0xff;
2699 COLORFILL_ROW(DWORD
);
2703 FIXME("Color fill not implemented for bpp %u!\n", bpp
* 8);
2704 return WINED3DERR_NOTAVAILABLE
;
2707 #undef COLORFILL_ROW
2709 /* Now copy first row. */
2711 for (y
= 1; y
< height
; ++y
)
2714 memcpy(buf
, first
, width
* bpp
);
2720 struct wined3d_surface
* CDECL
wined3d_surface_from_resource(struct wined3d_resource
*resource
)
2722 return surface_from_resource(resource
);
2725 HRESULT CDECL
wined3d_surface_unmap(struct wined3d_surface
*surface
)
2727 TRACE("surface %p.\n", surface
);
2729 if (!surface
->resource
.map_count
)
2731 WARN("Trying to unmap unmapped surface.\n");
2732 return WINEDDERR_NOTLOCKED
;
2734 --surface
->resource
.map_count
;
2736 surface
->surface_ops
->surface_unmap(surface
);
2741 HRESULT CDECL
wined3d_surface_map(struct wined3d_surface
*surface
,
2742 struct wined3d_map_desc
*map_desc
, const RECT
*rect
, DWORD flags
)
2744 const struct wined3d_format
*format
= surface
->resource
.format
;
2745 struct wined3d_device
*device
= surface
->resource
.device
;
2746 struct wined3d_context
*context
;
2747 const struct wined3d_gl_info
*gl_info
;
2750 TRACE("surface %p, map_desc %p, rect %s, flags %#x.\n",
2751 surface
, map_desc
, wine_dbgstr_rect(rect
), flags
);
2753 if (surface
->resource
.map_count
)
2755 WARN("Surface is already mapped.\n");
2756 return WINED3DERR_INVALIDCALL
;
2759 if ((format
->flags
& WINED3DFMT_FLAG_BLOCKS
) && rect
2760 && !surface_check_block_align(surface
, rect
))
2762 WARN("Map rect %s is misaligned for %ux%u blocks.\n",
2763 wine_dbgstr_rect(rect
), format
->block_width
, format
->block_height
);
2765 if (surface
->resource
.pool
== WINED3D_POOL_DEFAULT
)
2766 return WINED3DERR_INVALIDCALL
;
2769 ++surface
->resource
.map_count
;
2771 if (!(surface
->resource
.access_flags
& WINED3D_RESOURCE_ACCESS_CPU
))
2772 WARN("Trying to lock unlockable surface.\n");
2774 /* Performance optimization: Count how often a surface is mapped, if it is
2775 * mapped regularly do not throw away the system memory copy. This avoids
2776 * the need to download the surface from OpenGL all the time. The surface
2777 * is still downloaded if the OpenGL texture is changed. */
2778 if (!(surface
->flags
& SFLAG_DYNLOCK
) && surface
->resource
.map_binding
== WINED3D_LOCATION_SYSMEM
)
2780 if (++surface
->lockCount
> MAXLOCKCOUNT
)
2782 TRACE("Surface is mapped regularly, not freeing the system memory copy any more.\n");
2783 surface
->flags
|= SFLAG_DYNLOCK
;
2787 surface_prepare_map_memory(surface
);
2788 if (flags
& WINED3D_MAP_DISCARD
)
2790 TRACE("WINED3D_MAP_DISCARD flag passed, marking %s as up to date.\n",
2791 wined3d_debug_location(surface
->resource
.map_binding
));
2792 surface_validate_location(surface
, surface
->resource
.map_binding
);
2796 if (surface
->resource
.usage
& WINED3DUSAGE_DYNAMIC
)
2797 WARN_(d3d_perf
)("Mapping a dynamic surface without WINED3D_MAP_DISCARD.\n");
2799 surface_load_location(surface
, surface
->resource
.map_binding
);
2802 if (!(flags
& (WINED3D_MAP_NO_DIRTY_UPDATE
| WINED3D_MAP_READONLY
)))
2803 surface_invalidate_location(surface
, ~surface
->resource
.map_binding
);
2805 switch (surface
->resource
.map_binding
)
2807 case WINED3D_LOCATION_SYSMEM
:
2808 base_memory
= surface
->resource
.heap_memory
;
2811 case WINED3D_LOCATION_USER_MEMORY
:
2812 base_memory
= surface
->user_memory
;
2815 case WINED3D_LOCATION_DIB
:
2816 base_memory
= surface
->dib
.bitmap_data
;
2819 case WINED3D_LOCATION_BUFFER
:
2820 context
= context_acquire(device
, NULL
);
2821 gl_info
= context
->gl_info
;
2823 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->pbo
));
2824 base_memory
= GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, GL_READ_WRITE_ARB
));
2825 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
2826 checkGLcall("map PBO");
2828 context_release(context
);
2832 ERR("Unexpected map binding %s.\n", wined3d_debug_location(surface
->resource
.map_binding
));
2836 if (format
->flags
& WINED3DFMT_FLAG_BROKEN_PITCH
)
2837 map_desc
->row_pitch
= surface
->resource
.width
* format
->byte_count
;
2839 map_desc
->row_pitch
= wined3d_surface_get_pitch(surface
);
2840 map_desc
->slice_pitch
= 0;
2844 map_desc
->data
= base_memory
;
2845 surface
->lockedRect
.left
= 0;
2846 surface
->lockedRect
.top
= 0;
2847 surface
->lockedRect
.right
= surface
->resource
.width
;
2848 surface
->lockedRect
.bottom
= surface
->resource
.height
;
2852 if ((format
->flags
& (WINED3DFMT_FLAG_BLOCKS
| WINED3DFMT_FLAG_BROKEN_PITCH
)) == WINED3DFMT_FLAG_BLOCKS
)
2854 /* Compressed textures are block based, so calculate the offset of
2855 * the block that contains the top-left pixel of the locked rectangle. */
2856 map_desc
->data
= base_memory
2857 + ((rect
->top
/ format
->block_height
) * map_desc
->row_pitch
)
2858 + ((rect
->left
/ format
->block_width
) * format
->block_byte_count
);
2862 map_desc
->data
= base_memory
2863 + (map_desc
->row_pitch
* rect
->top
)
2864 + (rect
->left
* format
->byte_count
);
2866 surface
->lockedRect
.left
= rect
->left
;
2867 surface
->lockedRect
.top
= rect
->top
;
2868 surface
->lockedRect
.right
= rect
->right
;
2869 surface
->lockedRect
.bottom
= rect
->bottom
;
2872 TRACE("Locked rect %s.\n", wine_dbgstr_rect(&surface
->lockedRect
));
2873 TRACE("Returning memory %p, pitch %u.\n", map_desc
->data
, map_desc
->row_pitch
);
2878 HRESULT CDECL
wined3d_surface_getdc(struct wined3d_surface
*surface
, HDC
*dc
)
2882 TRACE("surface %p, dc %p.\n", surface
, dc
);
2884 /* Give more detailed info for ddraw. */
2885 if (surface
->flags
& SFLAG_DCINUSE
)
2886 return WINEDDERR_DCALREADYCREATED
;
2888 /* Can't GetDC if the surface is locked. */
2889 if (surface
->resource
.map_count
)
2890 return WINED3DERR_INVALIDCALL
;
2892 /* Create a DIB section if there isn't a dc yet. */
2895 if (surface
->flags
& SFLAG_CLIENT
)
2897 surface_load_location(surface
, WINED3D_LOCATION_SYSMEM
);
2898 surface_release_client_storage(surface
);
2900 hr
= surface_create_dib_section(surface
);
2902 return WINED3DERR_INVALIDCALL
;
2903 if (!(surface
->resource
.map_binding
== WINED3D_LOCATION_USER_MEMORY
2904 || surface
->flags
& SFLAG_PIN_SYSMEM
2906 surface
->resource
.map_binding
= WINED3D_LOCATION_DIB
;
2909 surface_load_location(surface
, WINED3D_LOCATION_DIB
);
2910 surface_invalidate_location(surface
, ~WINED3D_LOCATION_DIB
);
2912 surface
->flags
|= SFLAG_DCINUSE
;
2913 surface
->resource
.map_count
++;
2916 TRACE("Returning dc %p.\n", *dc
);
2921 HRESULT CDECL
wined3d_surface_releasedc(struct wined3d_surface
*surface
, HDC dc
)
2923 TRACE("surface %p, dc %p.\n", surface
, dc
);
2925 if (!(surface
->flags
& SFLAG_DCINUSE
))
2926 return WINEDDERR_NODC
;
2928 if (surface
->hDC
!= dc
)
2930 WARN("Application tries to release invalid DC %p, surface DC is %p.\n",
2932 return WINEDDERR_NODC
;
2935 surface
->resource
.map_count
--;
2936 surface
->flags
&= ~SFLAG_DCINUSE
;
2938 if (surface
->resource
.map_binding
== WINED3D_LOCATION_USER_MEMORY
|| (surface
->flags
& SFLAG_PIN_SYSMEM
2939 && surface
->resource
.map_binding
!= WINED3D_LOCATION_DIB
))
2941 /* The game Salammbo modifies the surface contents without mapping the surface between
2942 * a GetDC/ReleaseDC operation and flipping the surface. If the DIB remains the active
2943 * copy and is copied to the screen, this update, which draws the mouse pointer, is lost.
2944 * Do not only copy the DIB to the map location, but also make sure the map location is
2945 * copied back to the DIB in the next getdc call.
2947 * The same consideration applies to user memory surfaces. */
2948 surface_load_location(surface
, surface
->resource
.map_binding
);
2949 surface_invalidate_location(surface
, WINED3D_LOCATION_DIB
);
2955 static void read_from_framebuffer(struct wined3d_surface
*surface
, DWORD dst_location
)
2957 struct wined3d_device
*device
= surface
->resource
.device
;
2958 const struct wined3d_gl_info
*gl_info
;
2959 struct wined3d_context
*context
;
2961 BYTE
*row
, *top
, *bottom
;
2963 BOOL srcIsUpsideDown
;
2964 struct wined3d_bo_address data
;
2966 surface_get_memory(surface
, &data
, dst_location
);
2968 context
= context_acquire(device
, surface
);
2969 context_apply_blit_state(context
, device
);
2970 gl_info
= context
->gl_info
;
2972 /* Select the correct read buffer, and give some debug output.
2973 * There is no need to keep track of the current read buffer or reset it, every part of the code
2974 * that reads sets the read buffer as desired.
2976 if (wined3d_resource_is_offscreen(&surface
->container
->resource
))
2978 /* Mapping the primary render target which is not on a swapchain.
2979 * Read from the back buffer. */
2980 TRACE("Mapping offscreen render target.\n");
2981 gl_info
->gl_ops
.gl
.p_glReadBuffer(device
->offscreenBuffer
);
2982 srcIsUpsideDown
= TRUE
;
2986 /* Onscreen surfaces are always part of a swapchain */
2987 GLenum buffer
= surface_get_gl_buffer(surface
);
2988 TRACE("Mapping %#x buffer.\n", buffer
);
2989 gl_info
->gl_ops
.gl
.p_glReadBuffer(buffer
);
2990 checkGLcall("glReadBuffer");
2991 srcIsUpsideDown
= FALSE
;
2994 if (data
.buffer_object
)
2996 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, data
.buffer_object
));
2997 checkGLcall("glBindBufferARB");
3000 /* Setup pixel store pack state -- to glReadPixels into the correct place */
3001 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_PACK_ROW_LENGTH
, surface
->resource
.width
);
3002 checkGLcall("glPixelStorei");
3004 gl_info
->gl_ops
.gl
.p_glReadPixels(0, 0,
3005 surface
->resource
.width
, surface
->resource
.height
,
3006 surface
->resource
.format
->glFormat
,
3007 surface
->resource
.format
->glType
, data
.addr
);
3008 checkGLcall("glReadPixels");
3010 /* Reset previous pixel store pack state */
3011 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_PACK_ROW_LENGTH
, 0);
3012 checkGLcall("glPixelStorei");
3014 if (!srcIsUpsideDown
)
3016 /* glReadPixels returns the image upside down, and there is no way to prevent this.
3017 * Flip the lines in software. */
3018 UINT pitch
= wined3d_surface_get_pitch(surface
);
3020 if (!(row
= HeapAlloc(GetProcessHeap(), 0, pitch
)))
3023 if (data
.buffer_object
)
3025 mem
= GL_EXTCALL(glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, GL_READ_WRITE_ARB
));
3026 checkGLcall("glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_WRITE_ARB)");
3032 bottom
= mem
+ pitch
* (surface
->resource
.height
- 1);
3033 for (i
= 0; i
< surface
->resource
.height
/ 2; i
++)
3035 memcpy(row
, top
, pitch
);
3036 memcpy(top
, bottom
, pitch
);
3037 memcpy(bottom
, row
, pitch
);
3041 HeapFree(GetProcessHeap(), 0, row
);
3043 if (data
.buffer_object
)
3044 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB
));
3048 if (data
.buffer_object
)
3050 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, 0));
3051 checkGLcall("glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0)");
3054 context_release(context
);
3057 /* Read the framebuffer contents into a texture. Note that this function
3058 * doesn't do any kind of flipping. Using this on an onscreen surface will
3059 * result in a flipped D3D texture. */
3060 void surface_load_fb_texture(struct wined3d_surface
*surface
, BOOL srgb
)
3062 struct wined3d_device
*device
= surface
->resource
.device
;
3063 const struct wined3d_gl_info
*gl_info
;
3064 struct wined3d_context
*context
;
3066 context
= context_acquire(device
, surface
);
3067 gl_info
= context
->gl_info
;
3068 device_invalidate_state(device
, STATE_FRAMEBUFFER
);
3070 surface_prepare_texture(surface
, context
, srgb
);
3071 wined3d_texture_bind_and_dirtify(surface
->container
, context
, srgb
);
3073 TRACE("Reading back offscreen render target %p.\n", surface
);
3075 if (wined3d_resource_is_offscreen(&surface
->container
->resource
))
3076 gl_info
->gl_ops
.gl
.p_glReadBuffer(device
->offscreenBuffer
);
3078 gl_info
->gl_ops
.gl
.p_glReadBuffer(surface_get_gl_buffer(surface
));
3079 checkGLcall("glReadBuffer");
3081 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(surface
->texture_target
, surface
->texture_level
,
3082 0, 0, 0, 0, surface
->resource
.width
, surface
->resource
.height
);
3083 checkGLcall("glCopyTexSubImage2D");
3085 context_release(context
);
3088 /* Context activation is done by the caller. */
3089 static void surface_prepare_texture_internal(struct wined3d_surface
*surface
,
3090 struct wined3d_context
*context
, BOOL srgb
)
3092 DWORD alloc_flag
= srgb
? SFLAG_SRGBALLOCATED
: SFLAG_ALLOCATED
;
3093 enum wined3d_conversion_type convert
;
3094 struct wined3d_format format
;
3096 if (surface
->flags
& alloc_flag
) return;
3098 d3dfmt_get_conv(surface
->container
, TRUE
, &format
, &convert
);
3099 if (convert
!= WINED3D_CT_NONE
|| format
.convert
)
3100 surface
->flags
|= SFLAG_CONVERTED
;
3101 else surface
->flags
&= ~SFLAG_CONVERTED
;
3103 wined3d_texture_bind_and_dirtify(surface
->container
, context
, srgb
);
3104 surface_allocate_surface(surface
, context
->gl_info
, &format
, srgb
);
3105 surface
->flags
|= alloc_flag
;
3108 /* Context activation is done by the caller. */
3109 void surface_prepare_texture(struct wined3d_surface
*surface
, struct wined3d_context
*context
, BOOL srgb
)
3111 struct wined3d_texture
*texture
= surface
->container
;
3112 UINT sub_count
= texture
->level_count
* texture
->layer_count
;
3115 TRACE("surface %p is a subresource of texture %p.\n", surface
, texture
);
3117 for (i
= 0; i
< sub_count
; ++i
)
3119 struct wined3d_surface
*s
= surface_from_resource(texture
->sub_resources
[i
]);
3120 surface_prepare_texture_internal(s
, context
, srgb
);
3126 void surface_prepare_rb(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
, BOOL multisample
)
3130 if (surface
->rb_multisample
)
3133 gl_info
->fbo_ops
.glGenRenderbuffers(1, &surface
->rb_multisample
);
3134 gl_info
->fbo_ops
.glBindRenderbuffer(GL_RENDERBUFFER
, surface
->rb_multisample
);
3135 gl_info
->fbo_ops
.glRenderbufferStorageMultisample(GL_RENDERBUFFER
, surface
->resource
.multisample_type
,
3136 surface
->resource
.format
->glInternal
, surface
->pow2Width
, surface
->pow2Height
);
3137 TRACE("Created multisample rb %u.\n", surface
->rb_multisample
);
3141 if (surface
->rb_resolved
)
3144 gl_info
->fbo_ops
.glGenRenderbuffers(1, &surface
->rb_resolved
);
3145 gl_info
->fbo_ops
.glBindRenderbuffer(GL_RENDERBUFFER
, surface
->rb_resolved
);
3146 gl_info
->fbo_ops
.glRenderbufferStorage(GL_RENDERBUFFER
, surface
->resource
.format
->glInternal
,
3147 surface
->pow2Width
, surface
->pow2Height
);
3148 TRACE("Created resolved rb %u.\n", surface
->rb_resolved
);
3152 static BOOL
color_in_range(const struct wined3d_color_key
*color_key
, DWORD color
)
3154 /* FIXME: Is this really how color keys are supposed to work? I think it
3155 * makes more sense to compare the individual channels. */
3156 return color
>= color_key
->color_space_low_value
3157 && color
<= color_key
->color_space_high_value
;
3160 static HRESULT
d3dfmt_convert_surface(const BYTE
*src
, BYTE
*dst
, UINT pitch
, UINT width
, UINT height
,
3161 UINT outpitch
, enum wined3d_conversion_type conversion_type
, struct wined3d_surface
*surface
)
3167 TRACE("src %p, dst %p, pitch %u, width %u, height %u, outpitch %u, conversion_type %#x, surface %p.\n",
3168 src
, dst
, pitch
, width
, height
, outpitch
, conversion_type
, surface
);
3170 switch (conversion_type
)
3173 if (surface
->container
->swapchain
&& surface
->container
->swapchain
->palette
)
3175 const struct wined3d_palette
*palette
= surface
->container
->swapchain
->palette
;
3176 for (y
= 0; y
< height
; y
++)
3178 source
= src
+ pitch
* y
;
3179 dest
= dst
+ outpitch
* y
;
3180 for (x
= 0; x
< width
; x
++)
3182 BYTE color
= *source
++;
3183 *dest
++ = palette
->colors
[color
].rgbBlue
;
3184 *dest
++ = palette
->colors
[color
].rgbGreen
;
3185 *dest
++ = palette
->colors
[color
].rgbRed
;
3192 /* This should probably use the system palette, but unless
3193 * the X server is running in P8 mode there is no such thing.
3194 * The probably best solution is to set the fixed 20 colors
3195 * from the default windows palette and set the rest to black,
3196 * white, or some ugly pink. For now use black for the entire
3197 * palette. Don't use pink everywhere. Age of Empires 2 draws
3198 * a front buffer filled with zeroes without a palette when
3199 * starting and we don't want the screen to flash in an ugly
3201 FIXME("P8 surface loaded without a palette.\n");
3202 for (y
= 0; y
< height
; ++y
)
3204 memset(&dst
[outpitch
* y
], 0, width
* 4);
3209 case WINED3D_CT_CK_B5G6R5
:
3210 for (y
= 0; y
< height
; ++y
)
3212 source
= src
+ pitch
* y
;
3213 dest
= dst
+ outpitch
* y
;
3214 for (x
= 0; x
< width
; ++x
)
3216 WORD color
= *(const WORD
*)source
;
3217 if (!color_in_range(&surface
->container
->src_blt_color_key
, color
))
3218 *(WORD
*)dest
= 0x8000 | ((color
& 0xffc0) >> 1) | (color
& 0x1f);
3220 *(WORD
*)dest
= ((color
& 0xffc0) >> 1) | (color
& 0x1f);
3227 case WINED3D_CT_CK_B5G5R5X1
:
3229 /* Converting X1R5G5B5 format to R5G5B5A1 to emulate color-keying. */
3232 TRACE("Color keyed 5551\n");
3233 for (y
= 0; y
< height
; y
++) {
3234 Source
= (const WORD
*)(src
+ y
* pitch
);
3235 Dest
= (WORD
*) (dst
+ y
* outpitch
);
3236 for (x
= 0; x
< width
; x
++ ) {
3237 WORD color
= *Source
++;
3239 if (!color_in_range(&surface
->container
->src_blt_color_key
, color
))
3242 *Dest
&= ~(1 << 15);
3249 case WINED3D_CT_CK_B8G8R8
:
3250 for (y
= 0; y
< height
; ++y
)
3252 source
= src
+ pitch
* y
;
3253 dest
= dst
+ outpitch
* y
;
3254 for (x
= 0; x
< width
; ++x
)
3256 DWORD color
= ((DWORD
)source
[2] << 16) | ((DWORD
)source
[1] << 8) | (DWORD
)source
[0];
3257 if (!color_in_range(&surface
->container
->src_blt_color_key
, color
))
3258 color
|= 0xff000000;
3259 *(DWORD
*)dest
= color
;
3266 case WINED3D_CT_CK_B8G8R8X8
:
3267 for (y
= 0; y
< height
; ++y
)
3269 source
= src
+ pitch
* y
;
3270 dest
= dst
+ outpitch
* y
;
3271 for (x
= 0; x
< width
; ++x
)
3273 DWORD color
= *(const DWORD
*)source
;
3274 if (color_in_range(&surface
->container
->src_blt_color_key
, color
))
3275 *(DWORD
*)dest
= color
& ~0xff000000;
3277 *(DWORD
*)dest
= color
| 0xff000000;
3284 case WINED3D_CT_CK_B8G8R8A8
:
3285 for (y
= 0; y
< height
; ++y
)
3287 source
= src
+ pitch
* y
;
3288 dest
= dst
+ outpitch
* y
;
3289 for (x
= 0; x
< width
; ++x
)
3291 DWORD color
= *(const DWORD
*)source
;
3292 if (color_in_range(&surface
->container
->src_blt_color_key
, color
))
3293 color
&= ~0xff000000;
3294 *(DWORD
*)dest
= color
;
3302 ERR("Unsupported conversion type %#x.\n", conversion_type
);
3307 void flip_surface(struct wined3d_surface
*front
, struct wined3d_surface
*back
)
3309 if (front
->container
->level_count
!= 1 || front
->container
->layer_count
!= 1
3310 || back
->container
->level_count
!= 1 || back
->container
->layer_count
!= 1)
3311 ERR("Flip between surfaces %p and %p not supported.\n", front
, back
);
3313 /* Flip the surface contents */
3318 front
->hDC
= back
->hDC
;
3322 /* Flip the DIBsection */
3324 HBITMAP tmp
= front
->dib
.DIBsection
;
3325 front
->dib
.DIBsection
= back
->dib
.DIBsection
;
3326 back
->dib
.DIBsection
= tmp
;
3329 /* Flip the surface data */
3333 tmp
= front
->dib
.bitmap_data
;
3334 front
->dib
.bitmap_data
= back
->dib
.bitmap_data
;
3335 back
->dib
.bitmap_data
= tmp
;
3337 tmp
= front
->resource
.heap_memory
;
3338 front
->resource
.heap_memory
= back
->resource
.heap_memory
;
3339 back
->resource
.heap_memory
= tmp
;
3344 GLuint tmp_pbo
= front
->pbo
;
3345 front
->pbo
= back
->pbo
;
3346 back
->pbo
= tmp_pbo
;
3349 /* Flip the opengl texture */
3353 tmp
= back
->container
->texture_rgb
.name
;
3354 back
->container
->texture_rgb
.name
= front
->container
->texture_rgb
.name
;
3355 front
->container
->texture_rgb
.name
= tmp
;
3357 tmp
= back
->container
->texture_srgb
.name
;
3358 back
->container
->texture_srgb
.name
= front
->container
->texture_srgb
.name
;
3359 front
->container
->texture_srgb
.name
= tmp
;
3361 tmp
= back
->rb_multisample
;
3362 back
->rb_multisample
= front
->rb_multisample
;
3363 front
->rb_multisample
= tmp
;
3365 tmp
= back
->rb_resolved
;
3366 back
->rb_resolved
= front
->rb_resolved
;
3367 front
->rb_resolved
= tmp
;
3369 resource_unload(&back
->resource
);
3370 resource_unload(&front
->resource
);
3374 DWORD tmp_flags
= back
->flags
;
3375 back
->flags
= front
->flags
;
3376 front
->flags
= tmp_flags
;
3378 tmp_flags
= back
->locations
;
3379 back
->locations
= front
->locations
;
3380 front
->locations
= tmp_flags
;
3384 /* Does a direct frame buffer -> texture copy. Stretching is done with single
3385 * pixel copy calls. */
3386 static void fb_copy_to_texture_direct(struct wined3d_surface
*dst_surface
, struct wined3d_surface
*src_surface
,
3387 const RECT
*src_rect
, const RECT
*dst_rect_in
, enum wined3d_texture_filter_type filter
)
3389 struct wined3d_device
*device
= dst_surface
->resource
.device
;
3390 const struct wined3d_gl_info
*gl_info
;
3392 struct wined3d_context
*context
;
3393 BOOL upsidedown
= FALSE
;
3394 RECT dst_rect
= *dst_rect_in
;
3396 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
3397 * glCopyTexSubImage is a bit picky about the parameters we pass to it
3399 if(dst_rect
.top
> dst_rect
.bottom
) {
3400 UINT tmp
= dst_rect
.bottom
;
3401 dst_rect
.bottom
= dst_rect
.top
;
3406 context
= context_acquire(device
, src_surface
);
3407 gl_info
= context
->gl_info
;
3408 context_apply_blit_state(context
, device
);
3409 wined3d_texture_load(dst_surface
->container
, context
, FALSE
);
3411 /* Bind the target texture */
3412 context_bind_texture(context
, dst_surface
->container
->target
, dst_surface
->container
->texture_rgb
.name
);
3413 if (wined3d_resource_is_offscreen(&src_surface
->container
->resource
))
3415 TRACE("Reading from an offscreen target\n");
3416 upsidedown
= !upsidedown
;
3417 gl_info
->gl_ops
.gl
.p_glReadBuffer(device
->offscreenBuffer
);
3421 gl_info
->gl_ops
.gl
.p_glReadBuffer(surface_get_gl_buffer(src_surface
));
3423 checkGLcall("glReadBuffer");
3425 xrel
= (float) (src_rect
->right
- src_rect
->left
) / (float) (dst_rect
.right
- dst_rect
.left
);
3426 yrel
= (float) (src_rect
->bottom
- src_rect
->top
) / (float) (dst_rect
.bottom
- dst_rect
.top
);
3428 if ((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
3430 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
3432 if (filter
!= WINED3D_TEXF_NONE
&& filter
!= WINED3D_TEXF_POINT
)
3433 ERR("Texture filtering not supported in direct blit.\n");
3435 else if ((filter
!= WINED3D_TEXF_NONE
&& filter
!= WINED3D_TEXF_POINT
)
3436 && ((yrel
- 1.0f
< -eps
) || (yrel
- 1.0f
> eps
)))
3438 ERR("Texture filtering not supported in direct blit\n");
3442 && !((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
3443 && !((yrel
- 1.0f
< -eps
) || (yrel
- 1.0f
> eps
)))
3445 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do. */
3446 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(dst_surface
->texture_target
, dst_surface
->texture_level
,
3447 dst_rect
.left
/*xoffset */, dst_rect
.top
/* y offset */,
3448 src_rect
->left
, src_surface
->resource
.height
- src_rect
->bottom
,
3449 dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
);
3454 UINT yoffset
= src_surface
->resource
.height
- src_rect
->top
+ dst_rect
.top
- 1;
3455 /* I have to process this row by row to swap the image,
3456 * otherwise it would be upside down, so stretching in y direction
3457 * doesn't cost extra time
3459 * However, stretching in x direction can be avoided if not necessary
3461 for(row
= dst_rect
.top
; row
< dst_rect
.bottom
; row
++) {
3462 if ((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
3464 /* Well, that stuff works, but it's very slow.
3465 * find a better way instead
3469 for (col
= dst_rect
.left
; col
< dst_rect
.right
; ++col
)
3471 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(dst_surface
->texture_target
, dst_surface
->texture_level
,
3472 dst_rect
.left
+ col
/* x offset */, row
/* y offset */,
3473 src_rect
->left
+ col
* xrel
, yoffset
- (int) (row
* yrel
), 1, 1);
3478 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(dst_surface
->texture_target
, dst_surface
->texture_level
,
3479 dst_rect
.left
/* x offset */, row
/* y offset */,
3480 src_rect
->left
, yoffset
- (int) (row
* yrel
), dst_rect
.right
- dst_rect
.left
, 1);
3484 checkGLcall("glCopyTexSubImage2D");
3486 context_release(context
);
3488 /* The texture is now most up to date - If the surface is a render target
3489 * and has a drawable, this path is never entered. */
3490 surface_validate_location(dst_surface
, WINED3D_LOCATION_TEXTURE_RGB
);
3491 surface_invalidate_location(dst_surface
, ~WINED3D_LOCATION_TEXTURE_RGB
);
3494 /* Uses the hardware to stretch and flip the image */
3495 static void fb_copy_to_texture_hwstretch(struct wined3d_surface
*dst_surface
, struct wined3d_surface
*src_surface
,
3496 const RECT
*src_rect
, const RECT
*dst_rect_in
, enum wined3d_texture_filter_type filter
)
3498 struct wined3d_device
*device
= dst_surface
->resource
.device
;
3499 GLuint src
, backup
= 0;
3500 float left
, right
, top
, bottom
; /* Texture coordinates */
3501 UINT fbwidth
= src_surface
->resource
.width
;
3502 UINT fbheight
= src_surface
->resource
.height
;
3503 const struct wined3d_gl_info
*gl_info
;
3504 struct wined3d_context
*context
;
3505 GLenum drawBuffer
= GL_BACK
;
3506 GLenum texture_target
;
3507 BOOL noBackBufferBackup
;
3509 BOOL upsidedown
= FALSE
;
3510 RECT dst_rect
= *dst_rect_in
;
3512 TRACE("Using hwstretch blit\n");
3513 /* Activate the Proper context for reading from the source surface, set it up for blitting */
3514 context
= context_acquire(device
, src_surface
);
3515 gl_info
= context
->gl_info
;
3516 context_apply_blit_state(context
, device
);
3517 wined3d_texture_load(dst_surface
->container
, context
, FALSE
);
3519 src_offscreen
= wined3d_resource_is_offscreen(&src_surface
->container
->resource
);
3520 noBackBufferBackup
= src_offscreen
&& wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
;
3521 if (!noBackBufferBackup
&& !src_surface
->container
->texture_rgb
.name
)
3523 /* Get it a description */
3524 wined3d_texture_load(src_surface
->container
, context
, FALSE
);
3527 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
3528 * This way we don't have to wait for the 2nd readback to finish to leave this function.
3530 if (context
->aux_buffers
>= 2)
3532 /* Got more than one aux buffer? Use the 2nd aux buffer */
3533 drawBuffer
= GL_AUX1
;
3535 else if ((!src_offscreen
|| device
->offscreenBuffer
== GL_BACK
) && context
->aux_buffers
>= 1)
3537 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
3538 drawBuffer
= GL_AUX0
;
3541 if (noBackBufferBackup
)
3543 gl_info
->gl_ops
.gl
.p_glGenTextures(1, &backup
);
3544 checkGLcall("glGenTextures");
3545 context_bind_texture(context
, GL_TEXTURE_2D
, backup
);
3546 texture_target
= GL_TEXTURE_2D
;
3550 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
3551 * we are reading from the back buffer, the backup can be used as source texture
3553 texture_target
= src_surface
->texture_target
;
3554 context_bind_texture(context
, texture_target
, src_surface
->container
->texture_rgb
.name
);
3555 gl_info
->gl_ops
.gl
.p_glEnable(texture_target
);
3556 checkGLcall("glEnable(texture_target)");
3558 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
3559 src_surface
->locations
&= ~WINED3D_LOCATION_TEXTURE_RGB
;
3562 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
3563 * glCopyTexSubImage is a bit picky about the parameters we pass to it
3565 if(dst_rect
.top
> dst_rect
.bottom
) {
3566 UINT tmp
= dst_rect
.bottom
;
3567 dst_rect
.bottom
= dst_rect
.top
;
3574 TRACE("Reading from an offscreen target\n");
3575 upsidedown
= !upsidedown
;
3576 gl_info
->gl_ops
.gl
.p_glReadBuffer(device
->offscreenBuffer
);
3580 gl_info
->gl_ops
.gl
.p_glReadBuffer(surface_get_gl_buffer(src_surface
));
3583 /* TODO: Only back up the part that will be overwritten */
3584 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(texture_target
, 0, 0, 0, 0, 0, fbwidth
, fbheight
);
3586 checkGLcall("glCopyTexSubImage2D");
3588 /* No issue with overriding these - the sampler is dirty due to blit usage */
3589 gl_info
->gl_ops
.gl
.p_glTexParameteri(texture_target
, GL_TEXTURE_MAG_FILTER
,
3590 wined3d_gl_mag_filter(magLookup
, filter
));
3591 checkGLcall("glTexParameteri");
3592 gl_info
->gl_ops
.gl
.p_glTexParameteri(texture_target
, GL_TEXTURE_MIN_FILTER
,
3593 wined3d_gl_min_mip_filter(minMipLookup
, filter
, WINED3D_TEXF_NONE
));
3594 checkGLcall("glTexParameteri");
3596 if (!src_surface
->container
->swapchain
3597 || src_surface
->container
== src_surface
->container
->swapchain
->back_buffers
[0])
3599 src
= backup
? backup
: src_surface
->container
->texture_rgb
.name
;
3603 gl_info
->gl_ops
.gl
.p_glReadBuffer(GL_FRONT
);
3604 checkGLcall("glReadBuffer(GL_FRONT)");
3606 gl_info
->gl_ops
.gl
.p_glGenTextures(1, &src
);
3607 checkGLcall("glGenTextures(1, &src)");
3608 context_bind_texture(context
, GL_TEXTURE_2D
, src
);
3610 /* TODO: Only copy the part that will be read. Use src_rect->left, src_rect->bottom as origin, but with the width watch
3611 * out for power of 2 sizes
3613 gl_info
->gl_ops
.gl
.p_glTexImage2D(GL_TEXTURE_2D
, 0, GL_RGBA
, src_surface
->pow2Width
,
3614 src_surface
->pow2Height
, 0, GL_RGBA
, GL_UNSIGNED_BYTE
, NULL
);
3615 checkGLcall("glTexImage2D");
3616 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(GL_TEXTURE_2D
, 0, 0, 0, 0, 0, fbwidth
, fbheight
);
3618 gl_info
->gl_ops
.gl
.p_glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
3619 checkGLcall("glTexParameteri");
3620 gl_info
->gl_ops
.gl
.p_glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
3621 checkGLcall("glTexParameteri");
3623 gl_info
->gl_ops
.gl
.p_glReadBuffer(GL_BACK
);
3624 checkGLcall("glReadBuffer(GL_BACK)");
3626 if (texture_target
!= GL_TEXTURE_2D
)
3628 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
3629 gl_info
->gl_ops
.gl
.p_glEnable(GL_TEXTURE_2D
);
3630 texture_target
= GL_TEXTURE_2D
;
3633 checkGLcall("glEnd and previous");
3635 left
= src_rect
->left
;
3636 right
= src_rect
->right
;
3640 top
= src_surface
->resource
.height
- src_rect
->top
;
3641 bottom
= src_surface
->resource
.height
- src_rect
->bottom
;
3645 top
= src_surface
->resource
.height
- src_rect
->bottom
;
3646 bottom
= src_surface
->resource
.height
- src_rect
->top
;
3649 if (src_surface
->flags
& SFLAG_NORMCOORD
)
3651 left
/= src_surface
->pow2Width
;
3652 right
/= src_surface
->pow2Width
;
3653 top
/= src_surface
->pow2Height
;
3654 bottom
/= src_surface
->pow2Height
;
3657 /* draw the source texture stretched and upside down. The correct surface is bound already */
3658 gl_info
->gl_ops
.gl
.p_glTexParameteri(texture_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP
);
3659 gl_info
->gl_ops
.gl
.p_glTexParameteri(texture_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP
);
3661 context_set_draw_buffer(context
, drawBuffer
);
3662 gl_info
->gl_ops
.gl
.p_glReadBuffer(drawBuffer
);
3664 gl_info
->gl_ops
.gl
.p_glBegin(GL_QUADS
);
3666 gl_info
->gl_ops
.gl
.p_glTexCoord2f(left
, bottom
);
3667 gl_info
->gl_ops
.gl
.p_glVertex2i(0, 0);
3670 gl_info
->gl_ops
.gl
.p_glTexCoord2f(left
, top
);
3671 gl_info
->gl_ops
.gl
.p_glVertex2i(0, dst_rect
.bottom
- dst_rect
.top
);
3674 gl_info
->gl_ops
.gl
.p_glTexCoord2f(right
, top
);
3675 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
);
3678 gl_info
->gl_ops
.gl
.p_glTexCoord2f(right
, bottom
);
3679 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
.right
- dst_rect
.left
, 0);
3680 gl_info
->gl_ops
.gl
.p_glEnd();
3681 checkGLcall("glEnd and previous");
3683 if (texture_target
!= dst_surface
->texture_target
)
3685 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
3686 gl_info
->gl_ops
.gl
.p_glEnable(dst_surface
->texture_target
);
3687 texture_target
= dst_surface
->texture_target
;
3690 /* Now read the stretched and upside down image into the destination texture */
3691 context_bind_texture(context
, texture_target
, dst_surface
->container
->texture_rgb
.name
);
3692 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(texture_target
,
3694 dst_rect
.left
, dst_rect
.top
, /* xoffset, yoffset */
3695 0, 0, /* We blitted the image to the origin */
3696 dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
);
3697 checkGLcall("glCopyTexSubImage2D");
3699 if (drawBuffer
== GL_BACK
)
3701 /* Write the back buffer backup back. */
3704 if (texture_target
!= GL_TEXTURE_2D
)
3706 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
3707 gl_info
->gl_ops
.gl
.p_glEnable(GL_TEXTURE_2D
);
3708 texture_target
= GL_TEXTURE_2D
;
3710 context_bind_texture(context
, GL_TEXTURE_2D
, backup
);
3714 if (texture_target
!= src_surface
->texture_target
)
3716 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
3717 gl_info
->gl_ops
.gl
.p_glEnable(src_surface
->texture_target
);
3718 texture_target
= src_surface
->texture_target
;
3720 context_bind_texture(context
, src_surface
->texture_target
, src_surface
->container
->texture_rgb
.name
);
3723 gl_info
->gl_ops
.gl
.p_glBegin(GL_QUADS
);
3725 gl_info
->gl_ops
.gl
.p_glTexCoord2f(0.0f
, 0.0f
);
3726 gl_info
->gl_ops
.gl
.p_glVertex2i(0, fbheight
);
3729 gl_info
->gl_ops
.gl
.p_glTexCoord2f(0.0f
, (float)fbheight
/ (float)src_surface
->pow2Height
);
3730 gl_info
->gl_ops
.gl
.p_glVertex2i(0, 0);
3733 gl_info
->gl_ops
.gl
.p_glTexCoord2f((float)fbwidth
/ (float)src_surface
->pow2Width
,
3734 (float)fbheight
/ (float)src_surface
->pow2Height
);
3735 gl_info
->gl_ops
.gl
.p_glVertex2i(fbwidth
, 0);
3738 gl_info
->gl_ops
.gl
.p_glTexCoord2f((float)fbwidth
/ (float)src_surface
->pow2Width
, 0.0f
);
3739 gl_info
->gl_ops
.gl
.p_glVertex2i(fbwidth
, fbheight
);
3740 gl_info
->gl_ops
.gl
.p_glEnd();
3742 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
3743 checkGLcall("glDisable(texture_target)");
3746 if (src
!= src_surface
->container
->texture_rgb
.name
&& src
!= backup
)
3748 gl_info
->gl_ops
.gl
.p_glDeleteTextures(1, &src
);
3749 checkGLcall("glDeleteTextures(1, &src)");
3753 gl_info
->gl_ops
.gl
.p_glDeleteTextures(1, &backup
);
3754 checkGLcall("glDeleteTextures(1, &backup)");
3757 if (wined3d_settings
.strict_draw_ordering
)
3758 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
3760 context_release(context
);
3762 /* The texture is now most up to date - If the surface is a render target
3763 * and has a drawable, this path is never entered. */
3764 surface_validate_location(dst_surface
, WINED3D_LOCATION_TEXTURE_RGB
);
3765 surface_invalidate_location(dst_surface
, ~WINED3D_LOCATION_TEXTURE_RGB
);
3768 /* Front buffer coordinates are always full screen coordinates, but our GL
3769 * drawable is limited to the window's client area. The sysmem and texture
3770 * copies do have the full screen size. Note that GL has a bottom-left
3771 * origin, while D3D has a top-left origin. */
3772 void surface_translate_drawable_coords(const struct wined3d_surface
*surface
, HWND window
, RECT
*rect
)
3774 UINT drawable_height
;
3776 if (surface
->container
->swapchain
&& surface
->container
== surface
->container
->swapchain
->front_buffer
)
3778 POINT offset
= {0, 0};
3781 ScreenToClient(window
, &offset
);
3782 OffsetRect(rect
, offset
.x
, offset
.y
);
3784 GetClientRect(window
, &windowsize
);
3785 drawable_height
= windowsize
.bottom
- windowsize
.top
;
3789 drawable_height
= surface
->resource
.height
;
3792 rect
->top
= drawable_height
- rect
->top
;
3793 rect
->bottom
= drawable_height
- rect
->bottom
;
3796 static void surface_blt_to_drawable(const struct wined3d_device
*device
,
3797 enum wined3d_texture_filter_type filter
, BOOL alpha_test
,
3798 struct wined3d_surface
*src_surface
, const RECT
*src_rect_in
,
3799 struct wined3d_surface
*dst_surface
, const RECT
*dst_rect_in
)
3801 const struct wined3d_gl_info
*gl_info
;
3802 struct wined3d_context
*context
;
3803 RECT src_rect
, dst_rect
;
3805 src_rect
= *src_rect_in
;
3806 dst_rect
= *dst_rect_in
;
3808 context
= context_acquire(device
, dst_surface
);
3809 gl_info
= context
->gl_info
;
3811 /* Make sure the surface is up-to-date. This should probably use
3812 * surface_load_location() and worry about the destination surface too,
3813 * unless we're overwriting it completely. */
3814 wined3d_texture_load(src_surface
->container
, context
, FALSE
);
3816 /* Activate the destination context, set it up for blitting */
3817 context_apply_blit_state(context
, device
);
3819 if (!wined3d_resource_is_offscreen(&dst_surface
->container
->resource
))
3820 surface_translate_drawable_coords(dst_surface
, context
->win_handle
, &dst_rect
);
3822 device
->blitter
->set_shader(device
->blit_priv
, context
, src_surface
);
3826 gl_info
->gl_ops
.gl
.p_glEnable(GL_ALPHA_TEST
);
3827 checkGLcall("glEnable(GL_ALPHA_TEST)");
3829 /* For P8 surfaces, the alpha component contains the palette index.
3830 * Which means that the colorkey is one of the palette entries. In
3831 * other cases pixels that should be masked away have alpha set to 0. */
3832 if (src_surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
)
3833 gl_info
->gl_ops
.gl
.p_glAlphaFunc(GL_NOTEQUAL
,
3834 (float)src_surface
->container
->src_blt_color_key
.color_space_low_value
/ 256.0f
);
3836 gl_info
->gl_ops
.gl
.p_glAlphaFunc(GL_NOTEQUAL
, 0.0f
);
3837 checkGLcall("glAlphaFunc");
3841 gl_info
->gl_ops
.gl
.p_glDisable(GL_ALPHA_TEST
);
3842 checkGLcall("glDisable(GL_ALPHA_TEST)");
3845 draw_textured_quad(src_surface
, context
, &src_rect
, &dst_rect
, filter
);
3849 gl_info
->gl_ops
.gl
.p_glDisable(GL_ALPHA_TEST
);
3850 checkGLcall("glDisable(GL_ALPHA_TEST)");
3853 /* Leave the opengl state valid for blitting */
3854 device
->blitter
->unset_shader(context
->gl_info
);
3856 if (wined3d_settings
.strict_draw_ordering
3857 || (dst_surface
->container
->swapchain
3858 && dst_surface
->container
->swapchain
->front_buffer
== dst_surface
->container
))
3859 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
3861 context_release(context
);
3864 HRESULT
surface_color_fill(struct wined3d_surface
*s
, const RECT
*rect
, const struct wined3d_color
*color
)
3866 struct wined3d_device
*device
= s
->resource
.device
;
3867 const struct blit_shader
*blitter
;
3869 blitter
= wined3d_select_blitter(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_COLOR_FILL
,
3870 NULL
, 0, 0, NULL
, rect
, s
->resource
.usage
, s
->resource
.pool
, s
->resource
.format
);
3873 FIXME("No blitter is capable of performing the requested color fill operation.\n");
3874 return WINED3DERR_INVALIDCALL
;
3877 return blitter
->color_fill(device
, s
, rect
, color
);
3880 static HRESULT
surface_blt_special(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
3881 struct wined3d_surface
*src_surface
, const RECT
*src_rect
, DWORD flags
, const WINEDDBLTFX
*DDBltFx
,
3882 enum wined3d_texture_filter_type filter
)
3884 struct wined3d_device
*device
= dst_surface
->resource
.device
;
3885 const struct wined3d_surface
*rt
= wined3d_rendertarget_view_get_surface(device
->fb
.render_targets
[0]);
3886 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
3887 struct wined3d_swapchain
*src_swapchain
, *dst_swapchain
;
3889 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, blt_fx %p, filter %s.\n",
3890 dst_surface
, wine_dbgstr_rect(dst_rect
), src_surface
, wine_dbgstr_rect(src_rect
),
3891 flags
, DDBltFx
, debug_d3dtexturefiltertype(filter
));
3893 /* Get the swapchain. One of the surfaces has to be a primary surface */
3894 if (dst_surface
->resource
.pool
== WINED3D_POOL_SYSTEM_MEM
)
3896 WARN("Destination is in sysmem, rejecting gl blt\n");
3897 return WINED3DERR_INVALIDCALL
;
3900 dst_swapchain
= dst_surface
->container
->swapchain
;
3904 if (src_surface
->resource
.pool
== WINED3D_POOL_SYSTEM_MEM
)
3906 WARN("Src is in sysmem, rejecting gl blt\n");
3907 return WINED3DERR_INVALIDCALL
;
3910 src_swapchain
= src_surface
->container
->swapchain
;
3914 src_swapchain
= NULL
;
3917 /* Early sort out of cases where no render target is used */
3918 if (!dst_swapchain
&& !src_swapchain
&& src_surface
!= rt
&& dst_surface
!= rt
)
3920 TRACE("No surface is render target, not using hardware blit.\n");
3921 return WINED3DERR_INVALIDCALL
;
3924 /* No destination color keying supported */
3925 if (flags
& (WINEDDBLT_KEYDEST
| WINEDDBLT_KEYDESTOVERRIDE
))
3927 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
3928 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
3929 return WINED3DERR_INVALIDCALL
;
3932 if (dst_swapchain
&& dst_swapchain
== src_swapchain
)
3934 FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
3935 return WINED3DERR_INVALIDCALL
;
3938 if (dst_swapchain
&& src_swapchain
)
3940 FIXME("Implement hardware blit between two different swapchains\n");
3941 return WINED3DERR_INVALIDCALL
;
3946 /* Handled with regular texture -> swapchain blit */
3947 if (src_surface
== rt
)
3948 TRACE("Blit from active render target to a swapchain\n");
3950 else if (src_swapchain
&& dst_surface
== rt
)
3952 FIXME("Implement blit from a swapchain to the active render target\n");
3953 return WINED3DERR_INVALIDCALL
;
3956 if ((src_swapchain
|| src_surface
== rt
) && !dst_swapchain
)
3958 /* Blit from render target to texture */
3961 /* P8 read back is not implemented */
3962 if (src_surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
3963 || dst_surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
)
3965 TRACE("P8 read back not supported by frame buffer to texture blit\n");
3966 return WINED3DERR_INVALIDCALL
;
3969 if (flags
& (WINEDDBLT_KEYSRC
| WINEDDBLT_KEYSRCOVERRIDE
))
3971 TRACE("Color keying not supported by frame buffer to texture blit\n");
3972 return WINED3DERR_INVALIDCALL
;
3973 /* Destination color key is checked above */
3976 if (dst_rect
->right
- dst_rect
->left
!= src_rect
->right
- src_rect
->left
)
3981 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
3982 * flip the image nor scale it.
3984 * -> If the app asks for an unscaled, upside down copy, just perform one glCopyTexSubImage2D call
3985 * -> If the app wants an image width an unscaled width, copy it line per line
3986 * -> If the app wants an image that is scaled on the x axis, and the destination rectangle is smaller
3987 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
3988 * back buffer. This is slower than reading line per line, thus not used for flipping
3989 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
3990 * pixel by pixel. */
3991 if (!stretchx
|| dst_rect
->right
- dst_rect
->left
> src_surface
->resource
.width
3992 || dst_rect
->bottom
- dst_rect
->top
> src_surface
->resource
.height
)
3994 TRACE("No stretching in x direction, using direct framebuffer -> texture copy.\n");
3995 fb_copy_to_texture_direct(dst_surface
, src_surface
, src_rect
, dst_rect
, filter
);
3999 TRACE("Using hardware stretching to flip / stretch the texture.\n");
4000 fb_copy_to_texture_hwstretch(dst_surface
, src_surface
, src_rect
, dst_rect
, filter
);
4003 surface_evict_sysmem(dst_surface
);
4007 else if (src_surface
)
4009 /* Blit from offscreen surface to render target */
4010 struct wined3d_color_key old_blt_key
= src_surface
->container
->src_blt_color_key
;
4011 DWORD old_color_key_flags
= src_surface
->container
->color_key_flags
;
4013 TRACE("Blt from surface %p to rendertarget %p\n", src_surface
, dst_surface
);
4015 if (!device
->blitter
->blit_supported(gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
4016 src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
4017 dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
))
4019 FIXME("Unsupported blit operation falling back to software\n");
4020 return WINED3DERR_INVALIDCALL
;
4023 /* Color keying: Check if we have to do a color keyed blt,
4024 * and if not check if a color key is activated.
4026 * Just modify the color keying parameters in the surface and restore them afterwards
4027 * The surface keeps track of the color key last used to load the opengl surface.
4028 * PreLoad will catch the change to the flags and color key and reload if necessary.
4030 if (flags
& WINEDDBLT_KEYSRC
)
4032 /* Use color key from surface */
4034 else if (flags
& WINEDDBLT_KEYSRCOVERRIDE
)
4036 /* Use color key from DDBltFx */
4037 wined3d_texture_set_color_key(src_surface
->container
, WINEDDSD_CKSRCBLT
, &DDBltFx
->ddckSrcColorkey
);
4041 /* Do not use color key */
4042 wined3d_texture_set_color_key(src_surface
->container
, WINEDDSD_CKSRCBLT
, NULL
);
4045 surface_blt_to_drawable(device
, filter
,
4046 flags
& (WINEDDBLT_KEYSRC
| WINEDDBLT_KEYSRCOVERRIDE
| WINEDDBLT_ALPHATEST
),
4047 src_surface
, src_rect
, dst_surface
, dst_rect
);
4049 /* Restore the color key parameters */
4050 wined3d_texture_set_color_key(src_surface
->container
, WINEDDSD_CKSRCBLT
,
4051 (old_color_key_flags
& WINEDDSD_CKSRCBLT
) ? &old_blt_key
: NULL
);
4053 surface_validate_location(dst_surface
, dst_surface
->container
->resource
.draw_binding
);
4054 surface_invalidate_location(dst_surface
, ~dst_surface
->container
->resource
.draw_binding
);
4059 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
4060 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
4061 return WINED3DERR_INVALIDCALL
;
4064 /* Context activation is done by the caller. */
4065 static void surface_depth_blt(const struct wined3d_surface
*surface
, struct wined3d_context
*context
,
4066 GLuint texture
, GLint x
, GLint y
, GLsizei w
, GLsizei h
, GLenum target
)
4068 struct wined3d_device
*device
= surface
->resource
.device
;
4069 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
4070 GLint compare_mode
= GL_NONE
;
4071 struct blt_info info
;
4072 GLint old_binding
= 0;
4075 gl_info
->gl_ops
.gl
.p_glPushAttrib(GL_ENABLE_BIT
| GL_DEPTH_BUFFER_BIT
| GL_COLOR_BUFFER_BIT
| GL_VIEWPORT_BIT
);
4077 gl_info
->gl_ops
.gl
.p_glDisable(GL_CULL_FACE
);
4078 gl_info
->gl_ops
.gl
.p_glDisable(GL_BLEND
);
4079 gl_info
->gl_ops
.gl
.p_glDisable(GL_ALPHA_TEST
);
4080 gl_info
->gl_ops
.gl
.p_glDisable(GL_SCISSOR_TEST
);
4081 gl_info
->gl_ops
.gl
.p_glDisable(GL_STENCIL_TEST
);
4082 gl_info
->gl_ops
.gl
.p_glEnable(GL_DEPTH_TEST
);
4083 gl_info
->gl_ops
.gl
.p_glDepthFunc(GL_ALWAYS
);
4084 gl_info
->gl_ops
.gl
.p_glDepthMask(GL_TRUE
);
4085 gl_info
->gl_ops
.gl
.p_glColorMask(GL_FALSE
, GL_FALSE
, GL_FALSE
, GL_FALSE
);
4086 gl_info
->gl_ops
.gl
.p_glViewport(x
, y
, w
, h
);
4087 gl_info
->gl_ops
.gl
.p_glDepthRange(0.0, 1.0);
4089 SetRect(&rect
, 0, h
, w
, 0);
4090 surface_get_blt_info(target
, &rect
, surface
->pow2Width
, surface
->pow2Height
, &info
);
4091 context_active_texture(context
, context
->gl_info
, 0);
4092 gl_info
->gl_ops
.gl
.p_glGetIntegerv(info
.binding
, &old_binding
);
4093 gl_info
->gl_ops
.gl
.p_glBindTexture(info
.bind_target
, texture
);
4094 if (gl_info
->supported
[ARB_SHADOW
])
4096 gl_info
->gl_ops
.gl
.p_glGetTexParameteriv(info
.bind_target
, GL_TEXTURE_COMPARE_MODE_ARB
, &compare_mode
);
4097 if (compare_mode
!= GL_NONE
)
4098 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_COMPARE_MODE_ARB
, GL_NONE
);
4101 device
->shader_backend
->shader_select_depth_blt(device
->shader_priv
,
4102 gl_info
, info
.tex_type
, &surface
->ds_current_size
);
4104 gl_info
->gl_ops
.gl
.p_glBegin(GL_TRIANGLE_STRIP
);
4105 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[0]);
4106 gl_info
->gl_ops
.gl
.p_glVertex2f(-1.0f
, -1.0f
);
4107 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[1]);
4108 gl_info
->gl_ops
.gl
.p_glVertex2f(1.0f
, -1.0f
);
4109 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[2]);
4110 gl_info
->gl_ops
.gl
.p_glVertex2f(-1.0f
, 1.0f
);
4111 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[3]);
4112 gl_info
->gl_ops
.gl
.p_glVertex2f(1.0f
, 1.0f
);
4113 gl_info
->gl_ops
.gl
.p_glEnd();
4115 if (compare_mode
!= GL_NONE
)
4116 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_COMPARE_MODE_ARB
, compare_mode
);
4117 gl_info
->gl_ops
.gl
.p_glBindTexture(info
.bind_target
, old_binding
);
4119 gl_info
->gl_ops
.gl
.p_glPopAttrib();
4121 device
->shader_backend
->shader_deselect_depth_blt(device
->shader_priv
, gl_info
);
4124 void surface_modify_ds_location(struct wined3d_surface
*surface
,
4125 DWORD location
, UINT w
, UINT h
)
4127 TRACE("surface %p, new location %#x, w %u, h %u.\n", surface
, location
, w
, h
);
4129 if (((surface
->locations
& WINED3D_LOCATION_TEXTURE_RGB
) && !(location
& WINED3D_LOCATION_TEXTURE_RGB
))
4130 || (!(surface
->locations
& WINED3D_LOCATION_TEXTURE_RGB
) && (location
& WINED3D_LOCATION_TEXTURE_RGB
)))
4131 wined3d_texture_set_dirty(surface
->container
);
4133 surface
->ds_current_size
.cx
= w
;
4134 surface
->ds_current_size
.cy
= h
;
4135 surface
->locations
= location
;
4138 /* Context activation is done by the caller. */
4139 void surface_load_ds_location(struct wined3d_surface
*surface
, struct wined3d_context
*context
, DWORD location
)
4141 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
4142 struct wined3d_device
*device
= surface
->resource
.device
;
4145 TRACE("surface %p, new location %#x.\n", surface
, location
);
4147 /* TODO: Make this work for modes other than FBO */
4148 if (wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
) return;
4150 if (!(surface
->locations
& location
))
4152 w
= surface
->ds_current_size
.cx
;
4153 h
= surface
->ds_current_size
.cy
;
4154 surface
->ds_current_size
.cx
= 0;
4155 surface
->ds_current_size
.cy
= 0;
4159 w
= surface
->resource
.width
;
4160 h
= surface
->resource
.height
;
4163 if (surface
->ds_current_size
.cx
== surface
->resource
.width
4164 && surface
->ds_current_size
.cy
== surface
->resource
.height
)
4166 TRACE("Location (%#x) is already up to date.\n", location
);
4170 if (surface
->current_renderbuffer
)
4172 FIXME("Not supported with fixed up depth stencil.\n");
4176 if (surface
->locations
& WINED3D_LOCATION_DISCARDED
)
4178 TRACE("Surface was discarded, no need copy data.\n");
4181 case WINED3D_LOCATION_TEXTURE_RGB
:
4182 surface_prepare_texture(surface
, context
, FALSE
);
4184 case WINED3D_LOCATION_RB_MULTISAMPLE
:
4185 surface_prepare_rb(surface
, gl_info
, TRUE
);
4187 case WINED3D_LOCATION_DRAWABLE
:
4191 FIXME("Unhandled location %#x\n", location
);
4193 surface
->locations
&= ~WINED3D_LOCATION_DISCARDED
;
4194 surface
->locations
|= location
;
4195 surface
->ds_current_size
.cx
= surface
->resource
.width
;
4196 surface
->ds_current_size
.cy
= surface
->resource
.height
;
4200 if (!surface
->locations
)
4202 FIXME("No up to date depth stencil location.\n");
4203 surface
->locations
|= location
;
4204 surface
->ds_current_size
.cx
= surface
->resource
.width
;
4205 surface
->ds_current_size
.cy
= surface
->resource
.height
;
4209 if (location
== WINED3D_LOCATION_TEXTURE_RGB
)
4211 GLint old_binding
= 0;
4214 /* The render target is allowed to be smaller than the depth/stencil
4215 * buffer, so the onscreen depth/stencil buffer is potentially smaller
4216 * than the offscreen surface. Don't overwrite the offscreen surface
4217 * with undefined data. */
4218 w
= min(w
, context
->swapchain
->desc
.backbuffer_width
);
4219 h
= min(h
, context
->swapchain
->desc
.backbuffer_height
);
4221 TRACE("Copying onscreen depth buffer to depth texture.\n");
4223 if (!device
->depth_blt_texture
)
4224 gl_info
->gl_ops
.gl
.p_glGenTextures(1, &device
->depth_blt_texture
);
4226 /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
4227 * directly on the FBO texture. That's because we need to flip. */
4228 context_apply_fbo_state_blit(context
, GL_FRAMEBUFFER
,
4229 surface_from_resource(wined3d_texture_get_sub_resource(context
->swapchain
->front_buffer
, 0)),
4230 NULL
, WINED3D_LOCATION_DRAWABLE
);
4231 if (surface
->texture_target
== GL_TEXTURE_RECTANGLE_ARB
)
4233 gl_info
->gl_ops
.gl
.p_glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB
, &old_binding
);
4234 bind_target
= GL_TEXTURE_RECTANGLE_ARB
;
4238 gl_info
->gl_ops
.gl
.p_glGetIntegerv(GL_TEXTURE_BINDING_2D
, &old_binding
);
4239 bind_target
= GL_TEXTURE_2D
;
4241 gl_info
->gl_ops
.gl
.p_glBindTexture(bind_target
, device
->depth_blt_texture
);
4242 /* We use GL_DEPTH_COMPONENT instead of the surface's specific
4243 * internal format, because the internal format might include stencil
4244 * data. In principle we should copy stencil data as well, but unless
4245 * the driver supports stencil export it's hard to do, and doesn't
4246 * seem to be needed in practice. If the hardware doesn't support
4247 * writing stencil data, the glCopyTexImage2D() call might trigger
4248 * software fallbacks. */
4249 gl_info
->gl_ops
.gl
.p_glCopyTexImage2D(bind_target
, 0, GL_DEPTH_COMPONENT
, 0, 0, w
, h
, 0);
4250 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
4251 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
4252 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
4253 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
4254 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_WRAP_R
, GL_CLAMP_TO_EDGE
);
4255 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_DEPTH_TEXTURE_MODE_ARB
, GL_LUMINANCE
);
4256 gl_info
->gl_ops
.gl
.p_glBindTexture(bind_target
, old_binding
);
4258 context_apply_fbo_state_blit(context
, GL_FRAMEBUFFER
,
4259 NULL
, surface
, WINED3D_LOCATION_TEXTURE_RGB
);
4260 context_set_draw_buffer(context
, GL_NONE
);
4262 /* Do the actual blit */
4263 surface_depth_blt(surface
, context
, device
->depth_blt_texture
, 0, 0, w
, h
, bind_target
);
4264 checkGLcall("depth_blt");
4266 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
4268 if (wined3d_settings
.strict_draw_ordering
)
4269 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
4271 else if (location
== WINED3D_LOCATION_DRAWABLE
)
4273 TRACE("Copying depth texture to onscreen depth buffer.\n");
4275 context_apply_fbo_state_blit(context
, GL_FRAMEBUFFER
,
4276 surface_from_resource(wined3d_texture_get_sub_resource(context
->swapchain
->front_buffer
, 0)),
4277 NULL
, WINED3D_LOCATION_DRAWABLE
);
4278 surface_depth_blt(surface
, context
, surface
->container
->texture_rgb
.name
,
4279 0, surface
->pow2Height
- h
, w
, h
, surface
->texture_target
);
4280 checkGLcall("depth_blt");
4282 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
4284 if (wined3d_settings
.strict_draw_ordering
)
4285 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
4289 ERR("Invalid location (%#x) specified.\n", location
);
4292 surface
->locations
|= location
;
4293 surface
->ds_current_size
.cx
= surface
->resource
.width
;
4294 surface
->ds_current_size
.cy
= surface
->resource
.height
;
4297 void surface_validate_location(struct wined3d_surface
*surface
, DWORD location
)
4299 TRACE("surface %p, location %s.\n", surface
, wined3d_debug_location(location
));
4301 surface
->locations
|= location
;
4304 void surface_invalidate_location(struct wined3d_surface
*surface
, DWORD location
)
4306 TRACE("surface %p, location %s.\n", surface
, wined3d_debug_location(location
));
4308 if (location
& (WINED3D_LOCATION_TEXTURE_RGB
| WINED3D_LOCATION_TEXTURE_SRGB
))
4309 wined3d_texture_set_dirty(surface
->container
);
4310 surface
->locations
&= ~location
;
4312 if (!surface
->locations
)
4313 ERR("Surface %p does not have any up to date location.\n", surface
);
4316 static DWORD
resource_access_from_location(DWORD location
)
4320 case WINED3D_LOCATION_SYSMEM
:
4321 case WINED3D_LOCATION_USER_MEMORY
:
4322 case WINED3D_LOCATION_DIB
:
4323 case WINED3D_LOCATION_BUFFER
:
4324 return WINED3D_RESOURCE_ACCESS_CPU
;
4326 case WINED3D_LOCATION_DRAWABLE
:
4327 case WINED3D_LOCATION_TEXTURE_SRGB
:
4328 case WINED3D_LOCATION_TEXTURE_RGB
:
4329 case WINED3D_LOCATION_RB_MULTISAMPLE
:
4330 case WINED3D_LOCATION_RB_RESOLVED
:
4331 return WINED3D_RESOURCE_ACCESS_GPU
;
4334 FIXME("Unhandled location %#x.\n", location
);
4339 static void surface_copy_simple_location(struct wined3d_surface
*surface
, DWORD location
)
4341 struct wined3d_device
*device
= surface
->resource
.device
;
4342 struct wined3d_context
*context
;
4343 const struct wined3d_gl_info
*gl_info
;
4344 struct wined3d_bo_address dst
, src
;
4345 UINT size
= surface
->resource
.size
;
4347 surface_get_memory(surface
, &dst
, location
);
4348 surface_get_memory(surface
, &src
, surface
->locations
);
4350 if (dst
.buffer_object
)
4352 context
= context_acquire(device
, NULL
);
4353 gl_info
= context
->gl_info
;
4354 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, dst
.buffer_object
));
4355 GL_EXTCALL(glBufferSubDataARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0, size
, src
.addr
));
4356 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
4357 checkGLcall("Upload PBO");
4358 context_release(context
);
4361 if (src
.buffer_object
)
4363 context
= context_acquire(device
, NULL
);
4364 gl_info
= context
->gl_info
;
4365 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, src
.buffer_object
));
4366 GL_EXTCALL(glGetBufferSubDataARB(GL_PIXEL_PACK_BUFFER_ARB
, 0, size
, dst
.addr
));
4367 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, 0));
4368 checkGLcall("Download PBO");
4369 context_release(context
);
4372 memcpy(dst
.addr
, src
.addr
, size
);
4375 static void surface_load_sysmem(struct wined3d_surface
*surface
,
4376 const struct wined3d_gl_info
*gl_info
, DWORD dst_location
)
4378 if (surface
->locations
& surface_simple_locations
)
4380 surface_copy_simple_location(surface
, dst_location
);
4384 if (surface
->locations
& (WINED3D_LOCATION_RB_MULTISAMPLE
| WINED3D_LOCATION_RB_RESOLVED
))
4385 surface_load_location(surface
, WINED3D_LOCATION_TEXTURE_RGB
);
4387 /* Download the surface to system memory. */
4388 if (surface
->locations
& (WINED3D_LOCATION_TEXTURE_RGB
| WINED3D_LOCATION_TEXTURE_SRGB
))
4390 struct wined3d_device
*device
= surface
->resource
.device
;
4391 struct wined3d_context
*context
;
4393 /* TODO: Use already acquired context when possible. */
4394 context
= context_acquire(device
, NULL
);
4396 wined3d_texture_bind_and_dirtify(surface
->container
, context
,
4397 !(surface
->locations
& WINED3D_LOCATION_TEXTURE_RGB
));
4398 surface_download_data(surface
, gl_info
, dst_location
);
4400 context_release(context
);
4405 if (surface
->locations
& WINED3D_LOCATION_DRAWABLE
)
4407 read_from_framebuffer(surface
, dst_location
);
4411 FIXME("Can't load surface %p with location flags %s into sysmem.\n",
4412 surface
, wined3d_debug_location(surface
->locations
));
4415 static HRESULT
surface_load_drawable(struct wined3d_surface
*surface
,
4416 const struct wined3d_gl_info
*gl_info
)
4420 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
4421 && wined3d_resource_is_offscreen(&surface
->container
->resource
))
4423 ERR("Trying to load offscreen surface into WINED3D_LOCATION_DRAWABLE.\n");
4424 return WINED3DERR_INVALIDCALL
;
4427 surface_get_rect(surface
, NULL
, &r
);
4428 surface_load_location(surface
, WINED3D_LOCATION_TEXTURE_RGB
);
4429 surface_blt_to_drawable(surface
->resource
.device
,
4430 WINED3D_TEXF_POINT
, FALSE
, surface
, &r
, surface
, &r
);
4435 static HRESULT
surface_load_texture(struct wined3d_surface
*surface
,
4436 const struct wined3d_gl_info
*gl_info
, BOOL srgb
)
4438 RECT src_rect
= {0, 0, surface
->resource
.width
, surface
->resource
.height
};
4439 struct wined3d_device
*device
= surface
->resource
.device
;
4440 enum wined3d_conversion_type convert
;
4441 struct wined3d_context
*context
;
4442 UINT width
, src_pitch
, dst_pitch
;
4443 struct wined3d_bo_address data
;
4444 struct wined3d_format format
;
4445 POINT dst_point
= {0, 0};
4448 if (wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
4449 && wined3d_resource_is_offscreen(&surface
->container
->resource
)
4450 && (surface
->locations
& WINED3D_LOCATION_DRAWABLE
))
4452 surface_load_fb_texture(surface
, srgb
);
4457 if (surface
->locations
& (WINED3D_LOCATION_TEXTURE_SRGB
| WINED3D_LOCATION_TEXTURE_RGB
)
4458 && (surface
->resource
.format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB
)
4459 && fbo_blit_supported(gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
4460 NULL
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
,
4461 NULL
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
))
4464 surface_blt_fbo(device
, WINED3D_TEXF_POINT
, surface
, WINED3D_LOCATION_TEXTURE_RGB
,
4465 &src_rect
, surface
, WINED3D_LOCATION_TEXTURE_SRGB
, &src_rect
);
4467 surface_blt_fbo(device
, WINED3D_TEXF_POINT
, surface
, WINED3D_LOCATION_TEXTURE_SRGB
,
4468 &src_rect
, surface
, WINED3D_LOCATION_TEXTURE_RGB
, &src_rect
);
4473 if (surface
->locations
& (WINED3D_LOCATION_RB_MULTISAMPLE
| WINED3D_LOCATION_RB_RESOLVED
)
4474 && (!srgb
|| (surface
->resource
.format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB
))
4475 && fbo_blit_supported(gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
4476 NULL
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
,
4477 NULL
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
))
4479 DWORD src_location
= surface
->locations
& WINED3D_LOCATION_RB_RESOLVED
?
4480 WINED3D_LOCATION_RB_RESOLVED
: WINED3D_LOCATION_RB_MULTISAMPLE
;
4481 DWORD dst_location
= srgb
? WINED3D_LOCATION_TEXTURE_SRGB
: WINED3D_LOCATION_TEXTURE_RGB
;
4482 RECT rect
= {0, 0, surface
->resource
.width
, surface
->resource
.height
};
4484 surface_blt_fbo(device
, WINED3D_TEXF_POINT
, surface
, src_location
,
4485 &rect
, surface
, dst_location
, &rect
);
4490 /* Upload from system memory */
4492 d3dfmt_get_conv(surface
->container
, TRUE
/* We need color keying */, &format
, &convert
);
4496 if ((surface
->locations
& (WINED3D_LOCATION_TEXTURE_RGB
| surface
->resource
.map_binding
))
4497 == WINED3D_LOCATION_TEXTURE_RGB
)
4499 /* Performance warning... */
4500 FIXME("Downloading RGB surface %p to reload it as sRGB.\n", surface
);
4501 surface_prepare_map_memory(surface
);
4502 surface_load_location(surface
, surface
->resource
.map_binding
);
4507 if ((surface
->locations
& (WINED3D_LOCATION_TEXTURE_SRGB
| surface
->resource
.map_binding
))
4508 == WINED3D_LOCATION_TEXTURE_SRGB
)
4510 /* Performance warning... */
4511 FIXME("Downloading sRGB surface %p to reload it as RGB.\n", surface
);
4512 surface_prepare_map_memory(surface
);
4513 surface_load_location(surface
, surface
->resource
.map_binding
);
4517 if (!(surface
->locations
& surface_simple_locations
))
4519 WARN("Trying to load a texture from sysmem, but no simple location is valid.\n");
4520 /* Lets hope we get it from somewhere... */
4521 surface_prepare_system_memory(surface
);
4522 surface_load_location(surface
, WINED3D_LOCATION_SYSMEM
);
4525 /* TODO: Use already acquired context when possible. */
4526 context
= context_acquire(device
, NULL
);
4528 surface_prepare_texture(surface
, context
, srgb
);
4529 wined3d_texture_bind_and_dirtify(surface
->container
, context
, srgb
);
4531 if (surface
->container
->color_key_flags
& WINEDDSD_CKSRCBLT
)
4533 surface
->flags
|= SFLAG_GLCKEY
;
4534 surface
->gl_color_key
= surface
->container
->src_blt_color_key
;
4536 else surface
->flags
&= ~SFLAG_GLCKEY
;
4538 width
= surface
->resource
.width
;
4539 src_pitch
= wined3d_surface_get_pitch(surface
);
4541 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
4542 * SFLAG_CONVERTED but it isn't set (yet) in all cases it is getting
4544 if ((convert
!= WINED3D_CT_NONE
|| format
.convert
) && surface
->pbo
)
4546 TRACE("Removing the pbo attached to surface %p.\n", surface
);
4548 if (surface
->flags
& SFLAG_DIBSECTION
)
4549 surface
->resource
.map_binding
= WINED3D_LOCATION_DIB
;
4551 surface
->resource
.map_binding
= WINED3D_LOCATION_SYSMEM
;
4553 surface_prepare_map_memory(surface
);
4554 surface_load_location(surface
, surface
->resource
.map_binding
);
4555 surface_remove_pbo(surface
, gl_info
);
4558 surface_get_memory(surface
, &data
, surface
->locations
);
4561 /* This code is entered for texture formats which need a fixup. */
4562 UINT height
= surface
->resource
.height
;
4564 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
4565 dst_pitch
= width
* format
.conv_byte_count
;
4566 dst_pitch
= (dst_pitch
+ device
->surface_alignment
- 1) & ~(device
->surface_alignment
- 1);
4568 if (!(mem
= HeapAlloc(GetProcessHeap(), 0, dst_pitch
* height
)))
4570 ERR("Out of memory (%u).\n", dst_pitch
* height
);
4571 context_release(context
);
4572 return E_OUTOFMEMORY
;
4574 format
.convert(data
.addr
, mem
, src_pitch
, src_pitch
* height
,
4575 dst_pitch
, dst_pitch
* height
, width
, height
, 1);
4576 format
.byte_count
= format
.conv_byte_count
;
4577 src_pitch
= dst_pitch
;
4580 else if (convert
!= WINED3D_CT_NONE
)
4582 /* This code is only entered for color keying fixups */
4583 UINT height
= surface
->resource
.height
;
4585 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
4586 dst_pitch
= width
* format
.conv_byte_count
;
4587 dst_pitch
= (dst_pitch
+ device
->surface_alignment
- 1) & ~(device
->surface_alignment
- 1);
4589 if (!(mem
= HeapAlloc(GetProcessHeap(), 0, dst_pitch
* height
)))
4591 ERR("Out of memory (%u).\n", dst_pitch
* height
);
4592 context_release(context
);
4593 return E_OUTOFMEMORY
;
4595 d3dfmt_convert_surface(data
.addr
, mem
, src_pitch
,
4596 width
, height
, dst_pitch
, convert
, surface
);
4597 format
.byte_count
= format
.conv_byte_count
;
4598 src_pitch
= dst_pitch
;
4602 surface_upload_data(surface
, gl_info
, &format
, &src_rect
, src_pitch
, &dst_point
, srgb
, &data
);
4604 context_release(context
);
4606 HeapFree(GetProcessHeap(), 0, mem
);
4611 static void surface_multisample_resolve(struct wined3d_surface
*surface
)
4613 RECT rect
= {0, 0, surface
->resource
.width
, surface
->resource
.height
};
4615 if (!(surface
->locations
& WINED3D_LOCATION_RB_MULTISAMPLE
))
4616 ERR("Trying to resolve multisampled surface %p, but location WINED3D_LOCATION_RB_MULTISAMPLE not current.\n",
4619 surface_blt_fbo(surface
->resource
.device
, WINED3D_TEXF_POINT
,
4620 surface
, WINED3D_LOCATION_RB_MULTISAMPLE
, &rect
, surface
, WINED3D_LOCATION_RB_RESOLVED
, &rect
);
4623 HRESULT
surface_load_location(struct wined3d_surface
*surface
, DWORD location
)
4625 struct wined3d_device
*device
= surface
->resource
.device
;
4626 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
4629 TRACE("surface %p, location %s.\n", surface
, wined3d_debug_location(location
));
4631 if (surface
->resource
.usage
& WINED3DUSAGE_DEPTHSTENCIL
)
4633 if (location
== WINED3D_LOCATION_TEXTURE_RGB
4634 && surface
->locations
& (WINED3D_LOCATION_DRAWABLE
| WINED3D_LOCATION_DISCARDED
))
4636 struct wined3d_context
*context
= context_acquire(device
, NULL
);
4637 surface_load_ds_location(surface
, context
, location
);
4638 context_release(context
);
4641 else if (location
& surface
->locations
4642 && surface
->container
->resource
.draw_binding
!= WINED3D_LOCATION_DRAWABLE
)
4644 /* Already up to date, nothing to do. */
4649 FIXME("Unimplemented copy from %s to %s for depth/stencil buffers.\n",
4650 wined3d_debug_location(surface
->locations
), wined3d_debug_location(location
));
4651 return WINED3DERR_INVALIDCALL
;
4655 if (surface
->locations
& location
)
4657 TRACE("Location already up to date.\n");
4661 if (WARN_ON(d3d_surface
))
4663 DWORD required_access
= resource_access_from_location(location
);
4664 if ((surface
->resource
.access_flags
& required_access
) != required_access
)
4665 WARN("Operation requires %#x access, but surface only has %#x.\n",
4666 required_access
, surface
->resource
.access_flags
);
4669 if (!surface
->locations
)
4671 ERR("Surface %p does not have any up to date location.\n", surface
);
4672 surface
->flags
|= SFLAG_LOST
;
4673 return WINED3DERR_DEVICELOST
;
4678 case WINED3D_LOCATION_DIB
:
4679 case WINED3D_LOCATION_USER_MEMORY
:
4680 case WINED3D_LOCATION_SYSMEM
:
4681 case WINED3D_LOCATION_BUFFER
:
4682 surface_load_sysmem(surface
, gl_info
, location
);
4685 case WINED3D_LOCATION_DRAWABLE
:
4686 if (FAILED(hr
= surface_load_drawable(surface
, gl_info
)))
4690 case WINED3D_LOCATION_RB_RESOLVED
:
4691 surface_multisample_resolve(surface
);
4694 case WINED3D_LOCATION_TEXTURE_RGB
:
4695 case WINED3D_LOCATION_TEXTURE_SRGB
:
4696 if (FAILED(hr
= surface_load_texture(surface
, gl_info
, location
== WINED3D_LOCATION_TEXTURE_SRGB
)))
4701 ERR("Don't know how to handle location %#x.\n", location
);
4705 surface_validate_location(surface
, location
);
4707 if (location
!= WINED3D_LOCATION_SYSMEM
&& (surface
->locations
& WINED3D_LOCATION_SYSMEM
))
4708 surface_evict_sysmem(surface
);
4713 static HRESULT
ffp_blit_alloc(struct wined3d_device
*device
) { return WINED3D_OK
; }
4714 /* Context activation is done by the caller. */
4715 static void ffp_blit_free(struct wined3d_device
*device
) { }
4717 /* Context activation is done by the caller. */
4718 static HRESULT
ffp_blit_set(void *blit_priv
, struct wined3d_context
*context
, const struct wined3d_surface
*surface
)
4720 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
4722 gl_info
->gl_ops
.gl
.p_glEnable(surface
->container
->target
);
4723 checkGLcall("glEnable(target)");
4728 /* Context activation is done by the caller. */
4729 static void ffp_blit_unset(const struct wined3d_gl_info
*gl_info
)
4731 gl_info
->gl_ops
.gl
.p_glDisable(GL_TEXTURE_2D
);
4732 checkGLcall("glDisable(GL_TEXTURE_2D)");
4733 if (gl_info
->supported
[ARB_TEXTURE_CUBE_MAP
])
4735 gl_info
->gl_ops
.gl
.p_glDisable(GL_TEXTURE_CUBE_MAP_ARB
);
4736 checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
4738 if (gl_info
->supported
[ARB_TEXTURE_RECTANGLE
])
4740 gl_info
->gl_ops
.gl
.p_glDisable(GL_TEXTURE_RECTANGLE_ARB
);
4741 checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
4745 static BOOL
ffp_blit_supported(const struct wined3d_gl_info
*gl_info
, enum wined3d_blit_op blit_op
,
4746 const RECT
*src_rect
, DWORD src_usage
, enum wined3d_pool src_pool
, const struct wined3d_format
*src_format
,
4747 const RECT
*dst_rect
, DWORD dst_usage
, enum wined3d_pool dst_pool
, const struct wined3d_format
*dst_format
)
4751 case WINED3D_BLIT_OP_COLOR_BLIT
:
4752 if (src_pool
== WINED3D_POOL_SYSTEM_MEM
|| dst_pool
== WINED3D_POOL_SYSTEM_MEM
)
4755 if (TRACE_ON(d3d_surface
) && TRACE_ON(d3d
))
4757 TRACE("Checking support for fixup:\n");
4758 dump_color_fixup_desc(src_format
->color_fixup
);
4761 /* We only support identity conversions. */
4762 if (!is_identity_fixup(src_format
->color_fixup
)
4763 || !is_identity_fixup(dst_format
->color_fixup
))
4765 TRACE("Fixups are not supported.\n");
4771 case WINED3D_BLIT_OP_COLOR_FILL
:
4772 if (dst_pool
== WINED3D_POOL_SYSTEM_MEM
)
4775 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
)
4777 if (!((dst_format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE
) || (dst_usage
& WINED3DUSAGE_RENDERTARGET
)))
4780 else if (!(dst_usage
& WINED3DUSAGE_RENDERTARGET
))
4782 TRACE("Color fill not supported\n");
4786 /* FIXME: We should reject color fills on formats with fixups,
4787 * but this would break P8 color fills for example. */
4791 case WINED3D_BLIT_OP_DEPTH_FILL
:
4795 TRACE("Unsupported blit_op=%d\n", blit_op
);
4800 static HRESULT
ffp_blit_color_fill(struct wined3d_device
*device
, struct wined3d_surface
*dst_surface
,
4801 const RECT
*dst_rect
, const struct wined3d_color
*color
)
4803 const RECT draw_rect
= {0, 0, dst_surface
->resource
.width
, dst_surface
->resource
.height
};
4804 struct wined3d_rendertarget_view
*view
;
4805 struct wined3d_fb_state fb
= {&view
, NULL
};
4808 if (FAILED(hr
= wined3d_rendertarget_view_create_from_surface(dst_surface
,
4809 NULL
, &wined3d_null_parent_ops
, &view
)))
4811 ERR("Failed to create rendertarget view, hr %#x.\n", hr
);
4815 device_clear_render_targets(device
, 1, &fb
, 1, dst_rect
, &draw_rect
, WINED3DCLEAR_TARGET
, color
, 0.0f
, 0);
4816 wined3d_rendertarget_view_decref(view
);
4821 static HRESULT
ffp_blit_depth_fill(struct wined3d_device
*device
, struct wined3d_surface
*dst_surface
,
4822 const RECT
*dst_rect
, float depth
)
4824 const RECT draw_rect
= {0, 0, dst_surface
->resource
.width
, dst_surface
->resource
.height
};
4825 struct wined3d_fb_state fb
= {NULL
, NULL
};
4828 if (FAILED(hr
= wined3d_rendertarget_view_create_from_surface(dst_surface
,
4829 NULL
, &wined3d_null_parent_ops
, &fb
.depth_stencil
)))
4831 ERR("Failed to create rendertarget view, hr %#x.\n", hr
);
4835 device_clear_render_targets(device
, 0, &fb
, 1, dst_rect
, &draw_rect
, WINED3DCLEAR_ZBUFFER
, 0, depth
, 0);
4836 wined3d_rendertarget_view_decref(fb
.depth_stencil
);
4841 const struct blit_shader ffp_blit
= {
4847 ffp_blit_color_fill
,
4848 ffp_blit_depth_fill
,
4851 static HRESULT
cpu_blit_alloc(struct wined3d_device
*device
)
4856 /* Context activation is done by the caller. */
4857 static void cpu_blit_free(struct wined3d_device
*device
)
4861 /* Context activation is done by the caller. */
4862 static HRESULT
cpu_blit_set(void *blit_priv
, struct wined3d_context
*context
, const struct wined3d_surface
*surface
)
4867 /* Context activation is done by the caller. */
4868 static void cpu_blit_unset(const struct wined3d_gl_info
*gl_info
)
4872 static BOOL
cpu_blit_supported(const struct wined3d_gl_info
*gl_info
, enum wined3d_blit_op blit_op
,
4873 const RECT
*src_rect
, DWORD src_usage
, enum wined3d_pool src_pool
, const struct wined3d_format
*src_format
,
4874 const RECT
*dst_rect
, DWORD dst_usage
, enum wined3d_pool dst_pool
, const struct wined3d_format
*dst_format
)
4876 if (blit_op
== WINED3D_BLIT_OP_COLOR_FILL
)
4884 static HRESULT
surface_cpu_blt_compressed(const BYTE
*src_data
, BYTE
*dst_data
,
4885 UINT src_pitch
, UINT dst_pitch
, UINT update_w
, UINT update_h
,
4886 const struct wined3d_format
*format
, DWORD flags
, const WINEDDBLTFX
*fx
)
4888 UINT row_block_count
;
4889 const BYTE
*src_row
;
4896 row_block_count
= (update_w
+ format
->block_width
- 1) / format
->block_width
;
4900 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
4902 memcpy(dst_row
, src_row
, row_block_count
* format
->block_byte_count
);
4903 src_row
+= src_pitch
;
4904 dst_row
+= dst_pitch
;
4910 if (flags
== WINEDDBLT_DDFX
&& fx
->dwDDFX
== WINEDDBLTFX_MIRRORUPDOWN
)
4912 src_row
+= (((update_h
/ format
->block_height
) - 1) * src_pitch
);
4916 case WINED3DFMT_DXT1
:
4917 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
4922 BYTE control_row
[4];
4925 const struct block
*s
= (const struct block
*)src_row
;
4926 struct block
*d
= (struct block
*)dst_row
;
4928 for (x
= 0; x
< row_block_count
; ++x
)
4930 d
[x
].color
[0] = s
[x
].color
[0];
4931 d
[x
].color
[1] = s
[x
].color
[1];
4932 d
[x
].control_row
[0] = s
[x
].control_row
[3];
4933 d
[x
].control_row
[1] = s
[x
].control_row
[2];
4934 d
[x
].control_row
[2] = s
[x
].control_row
[1];
4935 d
[x
].control_row
[3] = s
[x
].control_row
[0];
4937 src_row
-= src_pitch
;
4938 dst_row
+= dst_pitch
;
4942 case WINED3DFMT_DXT2
:
4943 case WINED3DFMT_DXT3
:
4944 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
4950 BYTE control_row
[4];
4953 const struct block
*s
= (const struct block
*)src_row
;
4954 struct block
*d
= (struct block
*)dst_row
;
4956 for (x
= 0; x
< row_block_count
; ++x
)
4958 d
[x
].alpha_row
[0] = s
[x
].alpha_row
[3];
4959 d
[x
].alpha_row
[1] = s
[x
].alpha_row
[2];
4960 d
[x
].alpha_row
[2] = s
[x
].alpha_row
[1];
4961 d
[x
].alpha_row
[3] = s
[x
].alpha_row
[0];
4962 d
[x
].color
[0] = s
[x
].color
[0];
4963 d
[x
].color
[1] = s
[x
].color
[1];
4964 d
[x
].control_row
[0] = s
[x
].control_row
[3];
4965 d
[x
].control_row
[1] = s
[x
].control_row
[2];
4966 d
[x
].control_row
[2] = s
[x
].control_row
[1];
4967 d
[x
].control_row
[3] = s
[x
].control_row
[0];
4969 src_row
-= src_pitch
;
4970 dst_row
+= dst_pitch
;
4975 FIXME("Compressed flip not implemented for format %s.\n",
4976 debug_d3dformat(format
->id
));
4981 FIXME("Unsupported blit on compressed surface (format %s, flags %#x, DDFX %#x).\n",
4982 debug_d3dformat(format
->id
), flags
, flags
& WINEDDBLT_DDFX
? fx
->dwDDFX
: 0);
4987 static HRESULT
surface_cpu_blt(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
4988 struct wined3d_surface
*src_surface
, const RECT
*src_rect
, DWORD flags
,
4989 const WINEDDBLTFX
*fx
, enum wined3d_texture_filter_type filter
)
4991 int bpp
, srcheight
, srcwidth
, dstheight
, dstwidth
, width
;
4992 const struct wined3d_format
*src_format
, *dst_format
;
4993 struct wined3d_texture
*src_texture
= NULL
;
4994 struct wined3d_map_desc dst_map
, src_map
;
4995 const BYTE
*sbase
= NULL
;
4996 HRESULT hr
= WINED3D_OK
;
5001 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
5002 dst_surface
, wine_dbgstr_rect(dst_rect
), src_surface
, wine_dbgstr_rect(src_rect
),
5003 flags
, fx
, debug_d3dtexturefiltertype(filter
));
5005 if (src_surface
== dst_surface
)
5007 wined3d_surface_map(dst_surface
, &dst_map
, NULL
, 0);
5009 src_format
= dst_surface
->resource
.format
;
5010 dst_format
= src_format
;
5014 dst_format
= dst_surface
->resource
.format
;
5017 if (dst_surface
->resource
.format
->id
!= src_surface
->resource
.format
->id
)
5019 if (!(src_texture
= surface_convert_format(src_surface
, dst_format
->id
)))
5021 /* The conv function writes a FIXME */
5022 WARN("Cannot convert source surface format to dest format.\n");
5025 src_surface
= surface_from_resource(wined3d_texture_get_sub_resource(src_texture
, 0));
5027 wined3d_surface_map(src_surface
, &src_map
, NULL
, WINED3D_MAP_READONLY
);
5028 src_format
= src_surface
->resource
.format
;
5032 src_format
= dst_format
;
5035 wined3d_surface_map(dst_surface
, &dst_map
, dst_rect
, 0);
5038 bpp
= dst_surface
->resource
.format
->byte_count
;
5039 srcheight
= src_rect
->bottom
- src_rect
->top
;
5040 srcwidth
= src_rect
->right
- src_rect
->left
;
5041 dstheight
= dst_rect
->bottom
- dst_rect
->top
;
5042 dstwidth
= dst_rect
->right
- dst_rect
->left
;
5043 width
= (dst_rect
->right
- dst_rect
->left
) * bpp
;
5046 sbase
= (BYTE
*)src_map
.data
5047 + ((src_rect
->top
/ src_format
->block_height
) * src_map
.row_pitch
)
5048 + ((src_rect
->left
/ src_format
->block_width
) * src_format
->block_byte_count
);
5049 if (src_surface
!= dst_surface
)
5050 dbuf
= dst_map
.data
;
5052 dbuf
= (BYTE
*)dst_map
.data
5053 + ((dst_rect
->top
/ dst_format
->block_height
) * dst_map
.row_pitch
)
5054 + ((dst_rect
->left
/ dst_format
->block_width
) * dst_format
->block_byte_count
);
5056 if (src_format
->flags
& dst_format
->flags
& WINED3DFMT_FLAG_BLOCKS
)
5058 TRACE("%s -> %s copy.\n", debug_d3dformat(src_format
->id
), debug_d3dformat(dst_format
->id
));
5060 if (src_surface
== dst_surface
)
5062 FIXME("Only plain blits supported on compressed surfaces.\n");
5067 if (srcheight
!= dstheight
|| srcwidth
!= dstwidth
)
5069 WARN("Stretching not supported on compressed surfaces.\n");
5070 hr
= WINED3DERR_INVALIDCALL
;
5074 if (!surface_check_block_align(src_surface
, src_rect
))
5076 WARN("Source rectangle not block-aligned.\n");
5077 hr
= WINED3DERR_INVALIDCALL
;
5081 if (!surface_check_block_align(dst_surface
, dst_rect
))
5083 WARN("Destination rectangle not block-aligned.\n");
5084 hr
= WINED3DERR_INVALIDCALL
;
5088 hr
= surface_cpu_blt_compressed(sbase
, dbuf
,
5089 src_map
.row_pitch
, dst_map
.row_pitch
, dstwidth
, dstheight
,
5090 src_format
, flags
, fx
);
5094 /* First, all the 'source-less' blits */
5095 if (flags
& WINEDDBLT_COLORFILL
)
5097 hr
= _Blt_ColorFill(dbuf
, dstwidth
, dstheight
, bpp
, dst_map
.row_pitch
, fx
->u5
.dwFillColor
);
5098 flags
&= ~WINEDDBLT_COLORFILL
;
5101 if (flags
& WINEDDBLT_DEPTHFILL
)
5103 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
5105 if (flags
& WINEDDBLT_ROP
)
5107 /* Catch some degenerate cases here. */
5111 hr
= _Blt_ColorFill(dbuf
, dstwidth
, dstheight
, bpp
, dst_map
.row_pitch
, 0);
5113 case 0xaa0029: /* No-op */
5116 hr
= _Blt_ColorFill(dbuf
, dstwidth
, dstheight
, bpp
, dst_map
.row_pitch
, ~0U);
5118 case SRCCOPY
: /* Well, we do that below? */
5121 FIXME("Unsupported raster op: %08x Pattern: %p\n", fx
->dwROP
, fx
->u5
.lpDDSPattern
);
5124 flags
&= ~WINEDDBLT_ROP
;
5126 if (flags
& WINEDDBLT_DDROPS
)
5128 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", fx
->dwDDROP
, fx
->u5
.lpDDSPattern
);
5130 /* Now the 'with source' blits. */
5133 int sx
, xinc
, sy
, yinc
;
5135 if (!dstwidth
|| !dstheight
) /* Hmm... stupid program? */
5138 if (filter
!= WINED3D_TEXF_NONE
&& filter
!= WINED3D_TEXF_POINT
5139 && (srcwidth
!= dstwidth
|| srcheight
!= dstheight
))
5141 /* Can happen when d3d9 apps do a StretchRect() call which isn't handled in GL. */
5142 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(filter
));
5145 xinc
= (srcwidth
<< 16) / dstwidth
;
5146 yinc
= (srcheight
<< 16) / dstheight
;
5150 /* No effects, we can cheat here. */
5151 if (dstwidth
== srcwidth
)
5153 if (dstheight
== srcheight
)
5155 /* No stretching in either direction. This needs to be as
5156 * fast as possible. */
5159 /* Check for overlapping surfaces. */
5160 if (src_surface
!= dst_surface
|| dst_rect
->top
< src_rect
->top
5161 || dst_rect
->right
<= src_rect
->left
|| src_rect
->right
<= dst_rect
->left
)
5163 /* No overlap, or dst above src, so copy from top downwards. */
5164 for (y
= 0; y
< dstheight
; ++y
)
5166 memcpy(dbuf
, sbuf
, width
);
5167 sbuf
+= src_map
.row_pitch
;
5168 dbuf
+= dst_map
.row_pitch
;
5171 else if (dst_rect
->top
> src_rect
->top
)
5173 /* Copy from bottom upwards. */
5174 sbuf
+= src_map
.row_pitch
* dstheight
;
5175 dbuf
+= dst_map
.row_pitch
* dstheight
;
5176 for (y
= 0; y
< dstheight
; ++y
)
5178 sbuf
-= src_map
.row_pitch
;
5179 dbuf
-= dst_map
.row_pitch
;
5180 memcpy(dbuf
, sbuf
, width
);
5185 /* Src and dst overlapping on the same line, use memmove. */
5186 for (y
= 0; y
< dstheight
; ++y
)
5188 memmove(dbuf
, sbuf
, width
);
5189 sbuf
+= src_map
.row_pitch
;
5190 dbuf
+= dst_map
.row_pitch
;
5196 /* Stretching in y direction only. */
5197 for (y
= sy
= 0; y
< dstheight
; ++y
, sy
+= yinc
)
5199 sbuf
= sbase
+ (sy
>> 16) * src_map
.row_pitch
;
5200 memcpy(dbuf
, sbuf
, width
);
5201 dbuf
+= dst_map
.row_pitch
;
5207 /* Stretching in X direction. */
5209 for (y
= sy
= 0; y
< dstheight
; ++y
, sy
+= yinc
)
5211 sbuf
= sbase
+ (sy
>> 16) * src_map
.row_pitch
;
5213 if ((sy
>> 16) == (last_sy
>> 16))
5215 /* This source row is the same as last source row -
5216 * Copy the already stretched row. */
5217 memcpy(dbuf
, dbuf
- dst_map
.row_pitch
, width
);
5221 #define STRETCH_ROW(type) \
5223 const type *s = (const type *)sbuf; \
5224 type *d = (type *)dbuf; \
5225 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
5226 d[x] = s[sx >> 16]; \
5244 for (x
= sx
= 0; x
< dstwidth
; x
++, sx
+= xinc
)
5248 s
= sbuf
+ 3 * (sx
>> 16);
5249 pixel
= s
[0] | (s
[1] << 8) | (s
[2] << 16);
5250 d
[0] = (pixel
) & 0xff;
5251 d
[1] = (pixel
>> 8) & 0xff;
5252 d
[2] = (pixel
>> 16) & 0xff;
5258 FIXME("Stretched blit not implemented for bpp %u!\n", bpp
* 8);
5259 hr
= WINED3DERR_NOTAVAILABLE
;
5264 dbuf
+= dst_map
.row_pitch
;
5271 LONG dstyinc
= dst_map
.row_pitch
, dstxinc
= bpp
;
5272 DWORD keylow
= 0xffffffff, keyhigh
= 0, keymask
= 0xffffffff;
5273 DWORD destkeylow
= 0x0, destkeyhigh
= 0xffffffff, destkeymask
= 0xffffffff;
5274 if (flags
& (WINEDDBLT_KEYSRC
| WINEDDBLT_KEYDEST
| WINEDDBLT_KEYSRCOVERRIDE
| WINEDDBLT_KEYDESTOVERRIDE
))
5276 /* The color keying flags are checked for correctness in ddraw */
5277 if (flags
& WINEDDBLT_KEYSRC
)
5279 keylow
= src_surface
->container
->src_blt_color_key
.color_space_low_value
;
5280 keyhigh
= src_surface
->container
->src_blt_color_key
.color_space_high_value
;
5282 else if (flags
& WINEDDBLT_KEYSRCOVERRIDE
)
5284 keylow
= fx
->ddckSrcColorkey
.color_space_low_value
;
5285 keyhigh
= fx
->ddckSrcColorkey
.color_space_high_value
;
5288 if (flags
& WINEDDBLT_KEYDEST
)
5290 /* Destination color keys are taken from the source surface! */
5291 destkeylow
= src_surface
->container
->dst_blt_color_key
.color_space_low_value
;
5292 destkeyhigh
= src_surface
->container
->dst_blt_color_key
.color_space_high_value
;
5294 else if (flags
& WINEDDBLT_KEYDESTOVERRIDE
)
5296 destkeylow
= fx
->ddckDestColorkey
.color_space_low_value
;
5297 destkeyhigh
= fx
->ddckDestColorkey
.color_space_high_value
;
5307 get_color_masks(src_format
, masks
);
5312 flags
&= ~(WINEDDBLT_KEYSRC
| WINEDDBLT_KEYDEST
| WINEDDBLT_KEYSRCOVERRIDE
| WINEDDBLT_KEYDESTOVERRIDE
);
5315 if (flags
& WINEDDBLT_DDFX
)
5317 BYTE
*dTopLeft
, *dTopRight
, *dBottomLeft
, *dBottomRight
, *tmp
;
5320 dTopRight
= dbuf
+ ((dstwidth
- 1) * bpp
);
5321 dBottomLeft
= dTopLeft
+ ((dstheight
- 1) * dst_map
.row_pitch
);
5322 dBottomRight
= dBottomLeft
+ ((dstwidth
- 1) * bpp
);
5324 if (fx
->dwDDFX
& WINEDDBLTFX_ARITHSTRETCHY
)
5326 /* I don't think we need to do anything about this flag */
5327 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
5329 if (fx
->dwDDFX
& WINEDDBLTFX_MIRRORLEFTRIGHT
)
5332 dTopRight
= dTopLeft
;
5335 dBottomRight
= dBottomLeft
;
5337 dstxinc
= dstxinc
* -1;
5339 if (fx
->dwDDFX
& WINEDDBLTFX_MIRRORUPDOWN
)
5342 dTopLeft
= dBottomLeft
;
5345 dTopRight
= dBottomRight
;
5347 dstyinc
= dstyinc
* -1;
5349 if (fx
->dwDDFX
& WINEDDBLTFX_NOTEARING
)
5351 /* I don't think we need to do anything about this flag */
5352 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
5354 if (fx
->dwDDFX
& WINEDDBLTFX_ROTATE180
)
5357 dBottomRight
= dTopLeft
;
5360 dBottomLeft
= dTopRight
;
5362 dstxinc
= dstxinc
* -1;
5363 dstyinc
= dstyinc
* -1;
5365 if (fx
->dwDDFX
& WINEDDBLTFX_ROTATE270
)
5368 dTopLeft
= dBottomLeft
;
5369 dBottomLeft
= dBottomRight
;
5370 dBottomRight
= dTopRight
;
5375 dstxinc
= dstxinc
* -1;
5377 if (fx
->dwDDFX
& WINEDDBLTFX_ROTATE90
)
5380 dTopLeft
= dTopRight
;
5381 dTopRight
= dBottomRight
;
5382 dBottomRight
= dBottomLeft
;
5387 dstyinc
= dstyinc
* -1;
5389 if (fx
->dwDDFX
& WINEDDBLTFX_ZBUFFERBASEDEST
)
5391 /* I don't think we need to do anything about this flag */
5392 WARN("flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
5395 flags
&= ~(WINEDDBLT_DDFX
);
5398 #define COPY_COLORKEY_FX(type) \
5401 type *d = (type *)dbuf, *dx, tmp; \
5402 for (y = sy = 0; y < dstheight; ++y, sy += yinc) \
5404 s = (const type *)(sbase + (sy >> 16) * src_map.row_pitch); \
5406 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
5408 tmp = s[sx >> 16]; \
5409 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
5410 && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
5414 dx = (type *)(((BYTE *)dx) + dstxinc); \
5416 d = (type *)(((BYTE *)d) + dstyinc); \
5423 COPY_COLORKEY_FX(BYTE
);
5426 COPY_COLORKEY_FX(WORD
);
5429 COPY_COLORKEY_FX(DWORD
);
5434 BYTE
*d
= dbuf
, *dx
;
5435 for (y
= sy
= 0; y
< dstheight
; ++y
, sy
+= yinc
)
5437 sbuf
= sbase
+ (sy
>> 16) * src_map
.row_pitch
;
5439 for (x
= sx
= 0; x
< dstwidth
; ++x
, sx
+= xinc
)
5441 DWORD pixel
, dpixel
= 0;
5442 s
= sbuf
+ 3 * (sx
>>16);
5443 pixel
= s
[0] | (s
[1] << 8) | (s
[2] << 16);
5444 dpixel
= dx
[0] | (dx
[1] << 8 ) | (dx
[2] << 16);
5445 if (((pixel
& keymask
) < keylow
|| (pixel
& keymask
) > keyhigh
)
5446 && ((dpixel
& keymask
) >= destkeylow
|| (dpixel
& keymask
) <= keyhigh
))
5448 dx
[0] = (pixel
) & 0xff;
5449 dx
[1] = (pixel
>> 8) & 0xff;
5450 dx
[2] = (pixel
>> 16) & 0xff;
5459 FIXME("%s color-keyed blit not implemented for bpp %u!\n",
5460 (flags
& WINEDDBLT_KEYSRC
) ? "Source" : "Destination", bpp
* 8);
5461 hr
= WINED3DERR_NOTAVAILABLE
;
5463 #undef COPY_COLORKEY_FX
5469 if (flags
&& FIXME_ON(d3d_surface
))
5471 FIXME("\tUnsupported flags: %#x.\n", flags
);
5475 wined3d_surface_unmap(dst_surface
);
5476 if (src_surface
&& src_surface
!= dst_surface
)
5477 wined3d_surface_unmap(src_surface
);
5478 /* Release the converted surface, if any. */
5480 wined3d_texture_decref(src_texture
);
5485 static HRESULT
cpu_blit_color_fill(struct wined3d_device
*device
, struct wined3d_surface
*dst_surface
,
5486 const RECT
*dst_rect
, const struct wined3d_color
*color
)
5488 static const RECT src_rect
;
5491 memset(&BltFx
, 0, sizeof(BltFx
));
5492 BltFx
.dwSize
= sizeof(BltFx
);
5493 BltFx
.u5
.dwFillColor
= wined3d_format_convert_from_float(dst_surface
, color
);
5494 return surface_cpu_blt(dst_surface
, dst_rect
, NULL
, &src_rect
,
5495 WINEDDBLT_COLORFILL
, &BltFx
, WINED3D_TEXF_POINT
);
5498 static HRESULT
cpu_blit_depth_fill(struct wined3d_device
*device
,
5499 struct wined3d_surface
*surface
, const RECT
*rect
, float depth
)
5501 FIXME("Depth filling not implemented by cpu_blit.\n");
5502 return WINED3DERR_INVALIDCALL
;
5505 const struct blit_shader cpu_blit
= {
5511 cpu_blit_color_fill
,
5512 cpu_blit_depth_fill
,
5515 HRESULT CDECL
wined3d_surface_blt(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect_in
,
5516 struct wined3d_surface
*src_surface
, const RECT
*src_rect_in
, DWORD flags
,
5517 const WINEDDBLTFX
*fx
, enum wined3d_texture_filter_type filter
)
5519 struct wined3d_swapchain
*src_swapchain
, *dst_swapchain
;
5520 struct wined3d_device
*device
= dst_surface
->resource
.device
;
5521 DWORD src_ds_flags
, dst_ds_flags
;
5522 RECT src_rect
, dst_rect
;
5523 BOOL scale
, convert
;
5524 enum wined3d_conversion_type dst_convert_type
;
5525 struct wined3d_format dst_conv_fmt
;
5527 static const DWORD simple_blit
= WINEDDBLT_ASYNC
5528 | WINEDDBLT_COLORFILL
5530 | WINEDDBLT_DEPTHFILL
5531 | WINEDDBLT_DONOTWAIT
;
5533 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
5534 dst_surface
, wine_dbgstr_rect(dst_rect_in
), src_surface
, wine_dbgstr_rect(src_rect_in
),
5535 flags
, fx
, debug_d3dtexturefiltertype(filter
));
5536 TRACE("Usage is %s.\n", debug_d3dusage(dst_surface
->resource
.usage
));
5540 TRACE("dwSize %#x.\n", fx
->dwSize
);
5541 TRACE("dwDDFX %#x.\n", fx
->dwDDFX
);
5542 TRACE("dwROP %#x.\n", fx
->dwROP
);
5543 TRACE("dwDDROP %#x.\n", fx
->dwDDROP
);
5544 TRACE("dwRotationAngle %#x.\n", fx
->dwRotationAngle
);
5545 TRACE("dwZBufferOpCode %#x.\n", fx
->dwZBufferOpCode
);
5546 TRACE("dwZBufferLow %#x.\n", fx
->dwZBufferLow
);
5547 TRACE("dwZBufferHigh %#x.\n", fx
->dwZBufferHigh
);
5548 TRACE("dwZBufferBaseDest %#x.\n", fx
->dwZBufferBaseDest
);
5549 TRACE("dwZDestConstBitDepth %#x.\n", fx
->dwZDestConstBitDepth
);
5550 TRACE("lpDDSZBufferDest %p.\n", fx
->u1
.lpDDSZBufferDest
);
5551 TRACE("dwZSrcConstBitDepth %#x.\n", fx
->dwZSrcConstBitDepth
);
5552 TRACE("lpDDSZBufferSrc %p.\n", fx
->u2
.lpDDSZBufferSrc
);
5553 TRACE("dwAlphaEdgeBlendBitDepth %#x.\n", fx
->dwAlphaEdgeBlendBitDepth
);
5554 TRACE("dwAlphaEdgeBlend %#x.\n", fx
->dwAlphaEdgeBlend
);
5555 TRACE("dwReserved %#x.\n", fx
->dwReserved
);
5556 TRACE("dwAlphaDestConstBitDepth %#x.\n", fx
->dwAlphaDestConstBitDepth
);
5557 TRACE("lpDDSAlphaDest %p.\n", fx
->u3
.lpDDSAlphaDest
);
5558 TRACE("dwAlphaSrcConstBitDepth %#x.\n", fx
->dwAlphaSrcConstBitDepth
);
5559 TRACE("lpDDSAlphaSrc %p.\n", fx
->u4
.lpDDSAlphaSrc
);
5560 TRACE("lpDDSPattern %p.\n", fx
->u5
.lpDDSPattern
);
5561 TRACE("ddckDestColorkey {%#x, %#x}.\n",
5562 fx
->ddckDestColorkey
.color_space_low_value
,
5563 fx
->ddckDestColorkey
.color_space_high_value
);
5564 TRACE("ddckSrcColorkey {%#x, %#x}.\n",
5565 fx
->ddckSrcColorkey
.color_space_low_value
,
5566 fx
->ddckSrcColorkey
.color_space_high_value
);
5569 if (dst_surface
->resource
.map_count
|| (src_surface
&& src_surface
->resource
.map_count
))
5571 WARN("Surface is busy, returning WINEDDERR_SURFACEBUSY.\n");
5572 return WINEDDERR_SURFACEBUSY
;
5575 surface_get_rect(dst_surface
, dst_rect_in
, &dst_rect
);
5577 if (dst_rect
.left
>= dst_rect
.right
|| dst_rect
.top
>= dst_rect
.bottom
5578 || dst_rect
.left
> dst_surface
->resource
.width
|| dst_rect
.left
< 0
5579 || dst_rect
.top
> dst_surface
->resource
.height
|| dst_rect
.top
< 0
5580 || dst_rect
.right
> dst_surface
->resource
.width
|| dst_rect
.right
< 0
5581 || dst_rect
.bottom
> dst_surface
->resource
.height
|| dst_rect
.bottom
< 0)
5583 WARN("The application gave us a bad destination rectangle.\n");
5584 return WINEDDERR_INVALIDRECT
;
5589 surface_get_rect(src_surface
, src_rect_in
, &src_rect
);
5591 if (src_rect
.left
>= src_rect
.right
|| src_rect
.top
>= src_rect
.bottom
5592 || src_rect
.left
> src_surface
->resource
.width
|| src_rect
.left
< 0
5593 || src_rect
.top
> src_surface
->resource
.height
|| src_rect
.top
< 0
5594 || src_rect
.right
> src_surface
->resource
.width
|| src_rect
.right
< 0
5595 || src_rect
.bottom
> src_surface
->resource
.height
|| src_rect
.bottom
< 0)
5597 WARN("Application gave us bad source rectangle for Blt.\n");
5598 return WINEDDERR_INVALIDRECT
;
5603 memset(&src_rect
, 0, sizeof(src_rect
));
5606 if (!fx
|| !(fx
->dwDDFX
))
5607 flags
&= ~WINEDDBLT_DDFX
;
5609 if (flags
& WINEDDBLT_WAIT
)
5610 flags
&= ~WINEDDBLT_WAIT
;
5612 if (flags
& WINEDDBLT_ASYNC
)
5614 static unsigned int once
;
5617 FIXME("Can't handle WINEDDBLT_ASYNC flag.\n");
5618 flags
&= ~WINEDDBLT_ASYNC
;
5621 /* WINEDDBLT_DONOTWAIT appeared in DX7. */
5622 if (flags
& WINEDDBLT_DONOTWAIT
)
5624 static unsigned int once
;
5627 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag.\n");
5628 flags
&= ~WINEDDBLT_DONOTWAIT
;
5631 if (!device
->d3d_initialized
)
5633 WARN("D3D not initialized, using fallback.\n");
5637 /* We want to avoid invalidating the sysmem location for converted
5638 * surfaces, since otherwise we'd have to convert the data back when
5640 d3dfmt_get_conv(dst_surface
->container
, TRUE
, &dst_conv_fmt
, &dst_convert_type
);
5641 if (dst_convert_type
!= WINED3D_CT_NONE
|| dst_conv_fmt
.convert
|| dst_surface
->flags
& SFLAG_CONVERTED
)
5643 WARN_(d3d_perf
)("Converted surface, using CPU blit.\n");
5647 if (flags
& ~simple_blit
)
5649 WARN_(d3d_perf
)("Using fallback for complex blit (%#x).\n", flags
);
5654 src_swapchain
= src_surface
->container
->swapchain
;
5656 src_swapchain
= NULL
;
5658 dst_swapchain
= dst_surface
->container
->swapchain
;
5660 /* This isn't strictly needed. FBO blits for example could deal with
5661 * cross-swapchain blits by first downloading the source to a texture
5662 * before switching to the destination context. We just have this here to
5663 * not have to deal with the issue, since cross-swapchain blits should be
5665 if (src_swapchain
&& dst_swapchain
&& src_swapchain
!= dst_swapchain
)
5667 FIXME("Using fallback for cross-swapchain blit.\n");
5672 && (src_rect
.right
- src_rect
.left
!= dst_rect
.right
- dst_rect
.left
5673 || src_rect
.bottom
- src_rect
.top
!= dst_rect
.bottom
- dst_rect
.top
);
5674 convert
= src_surface
&& src_surface
->resource
.format
->id
!= dst_surface
->resource
.format
->id
;
5676 dst_ds_flags
= dst_surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
5678 src_ds_flags
= src_surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
5682 if (src_ds_flags
|| dst_ds_flags
)
5684 if (flags
& WINEDDBLT_DEPTHFILL
)
5688 TRACE("Depth fill.\n");
5690 if (!surface_convert_depth_to_float(dst_surface
, fx
->u5
.dwFillDepth
, &depth
))
5691 return WINED3DERR_INVALIDCALL
;
5693 if (SUCCEEDED(wined3d_surface_depth_fill(dst_surface
, &dst_rect
, depth
)))
5698 if (src_ds_flags
!= dst_ds_flags
)
5700 WARN("Rejecting depth / stencil blit between incompatible formats.\n");
5701 return WINED3DERR_INVALIDCALL
;
5704 if (SUCCEEDED(wined3d_surface_depth_blt(src_surface
, src_surface
->container
->resource
.draw_binding
,
5705 &src_rect
, dst_surface
, dst_surface
->container
->resource
.draw_binding
, &dst_rect
)))
5711 /* In principle this would apply to depth blits as well, but we don't
5712 * implement those in the CPU blitter at the moment. */
5713 if ((dst_surface
->locations
& dst_surface
->resource
.map_binding
)
5714 && (!src_surface
|| (src_surface
->locations
& src_surface
->resource
.map_binding
)))
5717 TRACE("Not doing sysmem blit because of scaling.\n");
5719 TRACE("Not doing sysmem blit because of format conversion.\n");
5724 if (flags
& WINEDDBLT_COLORFILL
)
5726 struct wined3d_color color
;
5728 TRACE("Color fill.\n");
5730 if (!surface_convert_color_to_float(dst_surface
, fx
->u5
.dwFillColor
, &color
))
5733 if (SUCCEEDED(surface_color_fill(dst_surface
, &dst_rect
, &color
)))
5738 TRACE("Color blit.\n");
5741 if ((src_surface
->locations
& WINED3D_LOCATION_SYSMEM
)
5742 && !(dst_surface
->locations
& WINED3D_LOCATION_SYSMEM
))
5745 TRACE("Not doing upload because of scaling.\n");
5747 TRACE("Not doing upload because of format conversion.\n");
5750 POINT dst_point
= {dst_rect
.left
, dst_rect
.top
};
5752 if (SUCCEEDED(surface_upload_from_surface(dst_surface
, &dst_point
, src_surface
, &src_rect
)))
5754 if (!wined3d_resource_is_offscreen(&dst_surface
->container
->resource
))
5755 surface_load_location(dst_surface
, dst_surface
->container
->resource
.draw_binding
);
5761 /* Use present for back -> front blits. The idea behind this is
5762 * that present is potentially faster than a blit, in particular
5763 * when FBO blits aren't available. Some ddraw applications like
5764 * Half-Life and Prince of Persia 3D use Blt() from the backbuffer
5765 * to the frontbuffer instead of doing a Flip(). D3D8 and D3D9
5766 * applications can't blit directly to the frontbuffer. */
5767 if (dst_swapchain
&& dst_swapchain
->back_buffers
5768 && dst_surface
->container
== dst_swapchain
->front_buffer
5769 && src_surface
->container
== dst_swapchain
->back_buffers
[0])
5771 enum wined3d_swap_effect swap_effect
= dst_swapchain
->desc
.swap_effect
;
5773 TRACE("Using present for backbuffer -> frontbuffer blit.\n");
5775 /* Set the swap effect to COPY, we don't want the backbuffer
5776 * to become undefined. */
5777 dst_swapchain
->desc
.swap_effect
= WINED3D_SWAP_EFFECT_COPY
;
5778 wined3d_swapchain_present(dst_swapchain
, NULL
, NULL
, dst_swapchain
->win_handle
, NULL
, 0);
5779 dst_swapchain
->desc
.swap_effect
= swap_effect
;
5784 if (fbo_blit_supported(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
5785 &src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
5786 &dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
))
5788 TRACE("Using FBO blit.\n");
5790 surface_blt_fbo(device
, filter
,
5791 src_surface
, src_surface
->container
->resource
.draw_binding
, &src_rect
,
5792 dst_surface
, dst_surface
->container
->resource
.draw_binding
, &dst_rect
);
5793 surface_validate_location(dst_surface
, dst_surface
->container
->resource
.draw_binding
);
5794 surface_invalidate_location(dst_surface
, ~dst_surface
->container
->resource
.draw_binding
);
5799 if (arbfp_blit
.blit_supported(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
5800 &src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
5801 &dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
))
5803 TRACE("Using arbfp blit.\n");
5805 if (SUCCEEDED(arbfp_blit_surface(device
, filter
, src_surface
, &src_rect
, dst_surface
, &dst_rect
)))
5812 /* Special cases for render targets. */
5813 if (SUCCEEDED(surface_blt_special(dst_surface
, &dst_rect
, src_surface
, &src_rect
, flags
, fx
, filter
)))
5818 /* For the rest call the X11 surface implementation. For render targets
5819 * this should be implemented OpenGL accelerated in surface_blt_special(),
5820 * other blits are rather rare. */
5821 return surface_cpu_blt(dst_surface
, &dst_rect
, src_surface
, &src_rect
, flags
, fx
, filter
);
5824 static HRESULT
surface_init(struct wined3d_surface
*surface
, struct wined3d_texture
*container
,
5825 const struct wined3d_resource_desc
*desc
, GLenum target
, unsigned int level
, unsigned int layer
, DWORD flags
)
5827 struct wined3d_device
*device
= container
->resource
.device
;
5828 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
5829 const struct wined3d_format
*format
= wined3d_get_format(gl_info
, desc
->format
);
5830 UINT multisample_quality
= desc
->multisample_quality
;
5831 BOOL lockable
= flags
& WINED3D_SURFACE_MAPPABLE
;
5832 unsigned int resource_size
;
5835 if (multisample_quality
> 0)
5837 FIXME("multisample_quality set to %u, substituting 0.\n", multisample_quality
);
5838 multisample_quality
= 0;
5841 /* Quick lockable sanity check.
5842 * TODO: remove this after surfaces, usage and lockability have been debugged properly
5843 * this function is too deep to need to care about things like this.
5844 * Levels need to be checked too, since they all affect what can be done. */
5847 case WINED3D_POOL_MANAGED
:
5848 if (desc
->usage
& WINED3DUSAGE_DYNAMIC
)
5849 FIXME("Called with a pool of MANAGED and a usage of DYNAMIC which are mutually exclusive.\n");
5852 case WINED3D_POOL_DEFAULT
:
5853 if (lockable
&& !(desc
->usage
& (WINED3DUSAGE_DYNAMIC
5854 | WINED3DUSAGE_RENDERTARGET
| WINED3DUSAGE_DEPTHSTENCIL
)))
5855 WARN("Creating a lockable surface with a POOL of DEFAULT, that doesn't specify DYNAMIC usage.\n");
5858 case WINED3D_POOL_SCRATCH
:
5859 case WINED3D_POOL_SYSTEM_MEM
:
5863 FIXME("Unknown pool %#x.\n", desc
->pool
);
5867 if (desc
->usage
& WINED3DUSAGE_RENDERTARGET
&& desc
->pool
!= WINED3D_POOL_DEFAULT
)
5868 FIXME("Trying to create a render target that isn't in the default pool.\n");
5870 /* FIXME: Check that the format is supported by the device. */
5872 resource_size
= wined3d_format_calculate_size(format
, device
->surface_alignment
, desc
->width
, desc
->height
, 1);
5874 return WINED3DERR_INVALIDCALL
;
5876 if (device
->wined3d
->flags
& WINED3D_NO3D
)
5877 surface
->surface_ops
= &gdi_surface_ops
;
5879 surface
->surface_ops
= &surface_ops
;
5881 if (FAILED(hr
= resource_init(&surface
->resource
, device
, WINED3D_RTYPE_SURFACE
, format
,
5882 desc
->multisample_type
, multisample_quality
, desc
->usage
, desc
->pool
, desc
->width
, desc
->height
, 1,
5883 resource_size
, NULL
, &wined3d_null_parent_ops
, &surface_resource_ops
)))
5885 WARN("Failed to initialize resource, returning %#x.\n", hr
);
5889 surface
->container
= container
;
5890 surface_validate_location(surface
, WINED3D_LOCATION_SYSMEM
);
5891 list_init(&surface
->renderbuffers
);
5892 list_init(&surface
->overlays
);
5895 if (target
!= GL_TEXTURE_RECTANGLE_ARB
)
5896 surface
->flags
|= SFLAG_NORMCOORD
;
5897 if (flags
& WINED3D_SURFACE_DISCARD
)
5898 surface
->flags
|= SFLAG_DISCARD
;
5899 if (flags
& WINED3D_SURFACE_PIN_SYSMEM
)
5900 surface
->flags
|= SFLAG_PIN_SYSMEM
;
5901 if (lockable
|| desc
->format
== WINED3DFMT_D16_LOCKABLE
)
5902 surface
->resource
.access_flags
|= WINED3D_RESOURCE_ACCESS_CPU
;
5904 surface
->texture_target
= target
;
5905 surface
->texture_level
= level
;
5906 surface
->texture_layer
= layer
;
5908 /* Call the private setup routine */
5909 if (FAILED(hr
= surface
->surface_ops
->surface_private_setup(surface
)))
5911 ERR("Private setup failed, hr %#x.\n", hr
);
5912 surface_cleanup(surface
);
5916 /* Similar to lockable rendertargets above, creating the DIB section
5917 * during surface initialization prevents the sysmem pointer from changing
5918 * after a wined3d_surface_getdc() call. */
5919 if ((desc
->usage
& WINED3DUSAGE_OWNDC
) && !surface
->hDC
5920 && SUCCEEDED(surface_create_dib_section(surface
)))
5921 surface
->resource
.map_binding
= WINED3D_LOCATION_DIB
;
5923 if (surface
->resource
.map_binding
== WINED3D_LOCATION_DIB
)
5925 wined3d_resource_free_sysmem(&surface
->resource
);
5926 surface_validate_location(surface
, WINED3D_LOCATION_DIB
);
5927 surface_invalidate_location(surface
, WINED3D_LOCATION_SYSMEM
);
5933 HRESULT
wined3d_surface_create(struct wined3d_texture
*container
, const struct wined3d_resource_desc
*desc
,
5934 GLenum target
, unsigned int level
, unsigned int layer
, DWORD flags
, struct wined3d_surface
**surface
)
5936 struct wined3d_device_parent
*device_parent
= container
->resource
.device
->device_parent
;
5937 const struct wined3d_parent_ops
*parent_ops
;
5938 struct wined3d_surface
*object
;
5942 TRACE("container %p, width %u, height %u, format %s, usage %s (%#x), pool %s, "
5943 "multisample_type %#x, multisample_quality %u, target %#x, level %u, layer %u, flags %#x, surface %p.\n",
5944 container
, desc
->width
, desc
->height
, debug_d3dformat(desc
->format
),
5945 debug_d3dusage(desc
->usage
), desc
->usage
, debug_d3dpool(desc
->pool
),
5946 desc
->multisample_type
, desc
->multisample_quality
, target
, level
, layer
, flags
, surface
);
5948 if (!(object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
))))
5949 return E_OUTOFMEMORY
;
5951 if (FAILED(hr
= surface_init(object
, container
, desc
, target
, level
, layer
, flags
)))
5953 WARN("Failed to initialize surface, returning %#x.\n", hr
);
5954 HeapFree(GetProcessHeap(), 0, object
);
5958 if (FAILED(hr
= device_parent
->ops
->surface_created(device_parent
,
5959 wined3d_texture_get_parent(container
), object
, &parent
, &parent_ops
)))
5961 WARN("Failed to create surface parent, hr %#x.\n", hr
);
5962 wined3d_surface_destroy(object
);
5966 TRACE("Created surface %p, parent %p, parent_ops %p.\n", object
, parent
, parent_ops
);
5968 object
->resource
.parent
= parent
;
5969 object
->resource
.parent_ops
= parent_ops
;