Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygensurface.c
Go to the documentation of this file.
00001 /* 00002 * Copyright 1997-2000 Marcus Meissner 00003 * Copyright 1998-2000 Lionel Ulmer 00004 * Copyright 2000-2001 TransGaming Technologies Inc. 00005 * Copyright 2002-2005 Jason Edmeades 00006 * Copyright 2002-2003 Raphael Junqueira 00007 * Copyright 2004 Christian Costa 00008 * Copyright 2005 Oliver Stieber 00009 * Copyright 2006-2011 Stefan Dösinger for CodeWeavers 00010 * Copyright 2007-2008 Henri Verbeet 00011 * Copyright 2006-2008 Roderick Colenbrander 00012 * Copyright 2009-2011 Henri Verbeet for CodeWeavers 00013 * 00014 * This library is free software; you can redistribute it and/or 00015 * modify it under the terms of the GNU Lesser General Public 00016 * License as published by the Free Software Foundation; either 00017 * version 2.1 of the License, or (at your option) any later version. 00018 * 00019 * This library is distributed in the hope that it will be useful, 00020 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00021 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00022 * Lesser General Public License for more details. 00023 * 00024 * You should have received a copy of the GNU Lesser General Public 00025 * License along with this library; if not, write to the Free Software 00026 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00027 */ 00028 00029 #include "config.h" 00030 #include "wine/port.h" 00031 #include "wined3d_private.h" 00032 00033 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface); 00034 WINE_DECLARE_DEBUG_CHANNEL(d3d); 00035 00036 static HRESULT surface_cpu_blt(struct wined3d_surface *dst_surface, const RECT *dst_rect, 00037 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags, 00038 const WINEDDBLTFX *fx, enum wined3d_texture_filter_type filter); 00039 static HRESULT IWineD3DSurfaceImpl_BltOverride(struct wined3d_surface *dst_surface, const RECT *dst_rect, 00040 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags, const WINEDDBLTFX *fx, 00041 enum wined3d_texture_filter_type filter); 00042 00043 static void surface_cleanup(struct wined3d_surface *surface) 00044 { 00045 struct wined3d_surface *overlay, *cur; 00046 00047 TRACE("surface %p.\n", surface); 00048 00049 if (surface->texture_name || (surface->flags & SFLAG_PBO) 00050 || surface->rb_multisample || surface->rb_resolved 00051 || !list_empty(&surface->renderbuffers)) 00052 { 00053 struct wined3d_renderbuffer_entry *entry, *entry2; 00054 const struct wined3d_gl_info *gl_info; 00055 struct wined3d_context *context; 00056 00057 context = context_acquire(surface->resource.device, NULL); 00058 gl_info = context->gl_info; 00059 00060 ENTER_GL(); 00061 00062 if (surface->texture_name) 00063 { 00064 TRACE("Deleting texture %u.\n", surface->texture_name); 00065 glDeleteTextures(1, &surface->texture_name); 00066 } 00067 00068 if (surface->flags & SFLAG_PBO) 00069 { 00070 TRACE("Deleting PBO %u.\n", surface->pbo); 00071 GL_EXTCALL(glDeleteBuffersARB(1, &surface->pbo)); 00072 } 00073 00074 if (surface->rb_multisample) 00075 { 00076 TRACE("Deleting multisample renderbuffer %u.\n", surface->rb_multisample); 00077 gl_info->fbo_ops.glDeleteRenderbuffers(1, &surface->rb_multisample); 00078 } 00079 00080 if (surface->rb_resolved) 00081 { 00082 TRACE("Deleting resolved renderbuffer %u.\n", surface->rb_resolved); 00083 gl_info->fbo_ops.glDeleteRenderbuffers(1, &surface->rb_resolved); 00084 } 00085 00086 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &surface->renderbuffers, struct wined3d_renderbuffer_entry, entry) 00087 { 00088 TRACE("Deleting renderbuffer %u.\n", entry->id); 00089 gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id); 00090 HeapFree(GetProcessHeap(), 0, entry); 00091 } 00092 00093 LEAVE_GL(); 00094 00095 context_release(context); 00096 } 00097 00098 if (surface->flags & SFLAG_DIBSECTION) 00099 { 00100 DeleteDC(surface->hDC); 00101 DeleteObject(surface->dib.DIBsection); 00102 surface->dib.bitmap_data = NULL; 00103 surface->resource.allocatedMemory = NULL; 00104 } 00105 00106 if (surface->flags & SFLAG_USERPTR) 00107 wined3d_surface_set_mem(surface, NULL); 00108 if (surface->overlay_dest) 00109 list_remove(&surface->overlay_entry); 00110 00111 LIST_FOR_EACH_ENTRY_SAFE(overlay, cur, &surface->overlays, struct wined3d_surface, overlay_entry) 00112 { 00113 list_remove(&overlay->overlay_entry); 00114 overlay->overlay_dest = NULL; 00115 } 00116 00117 resource_cleanup(&surface->resource); 00118 } 00119 00120 void surface_update_draw_binding(struct wined3d_surface *surface) 00121 { 00122 if (!surface_is_offscreen(surface) || wined3d_settings.offscreen_rendering_mode != ORM_FBO) 00123 surface->draw_binding = SFLAG_INDRAWABLE; 00124 else if (surface->resource.multisample_type) 00125 surface->draw_binding = SFLAG_INRB_MULTISAMPLE; 00126 else 00127 surface->draw_binding = SFLAG_INTEXTURE; 00128 } 00129 00130 void surface_set_container(struct wined3d_surface *surface, enum wined3d_container_type type, void *container) 00131 { 00132 TRACE("surface %p, container %p.\n", surface, container); 00133 00134 if (!container && type != WINED3D_CONTAINER_NONE) 00135 ERR("Setting NULL container of type %#x.\n", type); 00136 00137 if (type == WINED3D_CONTAINER_SWAPCHAIN) 00138 { 00139 surface->get_drawable_size = get_drawable_size_swapchain; 00140 } 00141 else 00142 { 00143 switch (wined3d_settings.offscreen_rendering_mode) 00144 { 00145 case ORM_FBO: 00146 surface->get_drawable_size = get_drawable_size_fbo; 00147 break; 00148 00149 case ORM_BACKBUFFER: 00150 surface->get_drawable_size = get_drawable_size_backbuffer; 00151 break; 00152 00153 default: 00154 ERR("Unhandled offscreen rendering mode %#x.\n", wined3d_settings.offscreen_rendering_mode); 00155 return; 00156 } 00157 } 00158 00159 surface->container.type = type; 00160 surface->container.u.base = container; 00161 surface_update_draw_binding(surface); 00162 } 00163 00164 struct blt_info 00165 { 00166 GLenum binding; 00167 GLenum bind_target; 00168 enum tex_types tex_type; 00169 GLfloat coords[4][3]; 00170 }; 00171 00172 struct float_rect 00173 { 00174 float l; 00175 float t; 00176 float r; 00177 float b; 00178 }; 00179 00180 static inline void cube_coords_float(const RECT *r, UINT w, UINT h, struct float_rect *f) 00181 { 00182 f->l = ((r->left * 2.0f) / w) - 1.0f; 00183 f->t = ((r->top * 2.0f) / h) - 1.0f; 00184 f->r = ((r->right * 2.0f) / w) - 1.0f; 00185 f->b = ((r->bottom * 2.0f) / h) - 1.0f; 00186 } 00187 00188 static void surface_get_blt_info(GLenum target, const RECT *rect, GLsizei w, GLsizei h, struct blt_info *info) 00189 { 00190 GLfloat (*coords)[3] = info->coords; 00191 struct float_rect f; 00192 00193 switch (target) 00194 { 00195 default: 00196 FIXME("Unsupported texture target %#x\n", target); 00197 /* Fall back to GL_TEXTURE_2D */ 00198 case GL_TEXTURE_2D: 00199 info->binding = GL_TEXTURE_BINDING_2D; 00200 info->bind_target = GL_TEXTURE_2D; 00201 info->tex_type = tex_2d; 00202 coords[0][0] = (float)rect->left / w; 00203 coords[0][1] = (float)rect->top / h; 00204 coords[0][2] = 0.0f; 00205 00206 coords[1][0] = (float)rect->right / w; 00207 coords[1][1] = (float)rect->top / h; 00208 coords[1][2] = 0.0f; 00209 00210 coords[2][0] = (float)rect->left / w; 00211 coords[2][1] = (float)rect->bottom / h; 00212 coords[2][2] = 0.0f; 00213 00214 coords[3][0] = (float)rect->right / w; 00215 coords[3][1] = (float)rect->bottom / h; 00216 coords[3][2] = 0.0f; 00217 break; 00218 00219 case GL_TEXTURE_RECTANGLE_ARB: 00220 info->binding = GL_TEXTURE_BINDING_RECTANGLE_ARB; 00221 info->bind_target = GL_TEXTURE_RECTANGLE_ARB; 00222 info->tex_type = tex_rect; 00223 coords[0][0] = rect->left; coords[0][1] = rect->top; coords[0][2] = 0.0f; 00224 coords[1][0] = rect->right; coords[1][1] = rect->top; coords[1][2] = 0.0f; 00225 coords[2][0] = rect->left; coords[2][1] = rect->bottom; coords[2][2] = 0.0f; 00226 coords[3][0] = rect->right; coords[3][1] = rect->bottom; coords[3][2] = 0.0f; 00227 break; 00228 00229 case GL_TEXTURE_CUBE_MAP_POSITIVE_X: 00230 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB; 00231 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB; 00232 info->tex_type = tex_cube; 00233 cube_coords_float(rect, w, h, &f); 00234 00235 coords[0][0] = 1.0f; coords[0][1] = -f.t; coords[0][2] = -f.l; 00236 coords[1][0] = 1.0f; coords[1][1] = -f.t; coords[1][2] = -f.r; 00237 coords[2][0] = 1.0f; coords[2][1] = -f.b; coords[2][2] = -f.l; 00238 coords[3][0] = 1.0f; coords[3][1] = -f.b; coords[3][2] = -f.r; 00239 break; 00240 00241 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: 00242 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB; 00243 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB; 00244 info->tex_type = tex_cube; 00245 cube_coords_float(rect, w, h, &f); 00246 00247 coords[0][0] = -1.0f; coords[0][1] = -f.t; coords[0][2] = f.l; 00248 coords[1][0] = -1.0f; coords[1][1] = -f.t; coords[1][2] = f.r; 00249 coords[2][0] = -1.0f; coords[2][1] = -f.b; coords[2][2] = f.l; 00250 coords[3][0] = -1.0f; coords[3][1] = -f.b; coords[3][2] = f.r; 00251 break; 00252 00253 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: 00254 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB; 00255 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB; 00256 info->tex_type = tex_cube; 00257 cube_coords_float(rect, w, h, &f); 00258 00259 coords[0][0] = f.l; coords[0][1] = 1.0f; coords[0][2] = f.t; 00260 coords[1][0] = f.r; coords[1][1] = 1.0f; coords[1][2] = f.t; 00261 coords[2][0] = f.l; coords[2][1] = 1.0f; coords[2][2] = f.b; 00262 coords[3][0] = f.r; coords[3][1] = 1.0f; coords[3][2] = f.b; 00263 break; 00264 00265 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: 00266 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB; 00267 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB; 00268 info->tex_type = tex_cube; 00269 cube_coords_float(rect, w, h, &f); 00270 00271 coords[0][0] = f.l; coords[0][1] = -1.0f; coords[0][2] = -f.t; 00272 coords[1][0] = f.r; coords[1][1] = -1.0f; coords[1][2] = -f.t; 00273 coords[2][0] = f.l; coords[2][1] = -1.0f; coords[2][2] = -f.b; 00274 coords[3][0] = f.r; coords[3][1] = -1.0f; coords[3][2] = -f.b; 00275 break; 00276 00277 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: 00278 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB; 00279 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB; 00280 info->tex_type = tex_cube; 00281 cube_coords_float(rect, w, h, &f); 00282 00283 coords[0][0] = f.l; coords[0][1] = -f.t; coords[0][2] = 1.0f; 00284 coords[1][0] = f.r; coords[1][1] = -f.t; coords[1][2] = 1.0f; 00285 coords[2][0] = f.l; coords[2][1] = -f.b; coords[2][2] = 1.0f; 00286 coords[3][0] = f.r; coords[3][1] = -f.b; coords[3][2] = 1.0f; 00287 break; 00288 00289 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: 00290 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB; 00291 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB; 00292 info->tex_type = tex_cube; 00293 cube_coords_float(rect, w, h, &f); 00294 00295 coords[0][0] = -f.l; coords[0][1] = -f.t; coords[0][2] = -1.0f; 00296 coords[1][0] = -f.r; coords[1][1] = -f.t; coords[1][2] = -1.0f; 00297 coords[2][0] = -f.l; coords[2][1] = -f.b; coords[2][2] = -1.0f; 00298 coords[3][0] = -f.r; coords[3][1] = -f.b; coords[3][2] = -1.0f; 00299 break; 00300 } 00301 } 00302 00303 static void surface_get_rect(const struct wined3d_surface *surface, const RECT *rect_in, RECT *rect_out) 00304 { 00305 if (rect_in) 00306 *rect_out = *rect_in; 00307 else 00308 { 00309 rect_out->left = 0; 00310 rect_out->top = 0; 00311 rect_out->right = surface->resource.width; 00312 rect_out->bottom = surface->resource.height; 00313 } 00314 } 00315 00316 /* GL locking and context activation is done by the caller */ 00317 void draw_textured_quad(const struct wined3d_surface *src_surface, struct wined3d_context *context, 00318 const RECT *src_rect, const RECT *dst_rect, enum wined3d_texture_filter_type filter) 00319 { 00320 struct blt_info info; 00321 00322 surface_get_blt_info(src_surface->texture_target, src_rect, src_surface->pow2Width, src_surface->pow2Height, &info); 00323 00324 glEnable(info.bind_target); 00325 checkGLcall("glEnable(bind_target)"); 00326 00327 context_bind_texture(context, info.bind_target, src_surface->texture_name); 00328 00329 /* Filtering for StretchRect */ 00330 glTexParameteri(info.bind_target, GL_TEXTURE_MAG_FILTER, 00331 wined3d_gl_mag_filter(magLookup, filter)); 00332 checkGLcall("glTexParameteri"); 00333 glTexParameteri(info.bind_target, GL_TEXTURE_MIN_FILTER, 00334 wined3d_gl_min_mip_filter(minMipLookup, filter, WINED3D_TEXF_NONE)); 00335 checkGLcall("glTexParameteri"); 00336 glTexParameteri(info.bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP); 00337 glTexParameteri(info.bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP); 00338 if (context->gl_info->supported[EXT_TEXTURE_SRGB_DECODE]) 00339 glTexParameteri(info.bind_target, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT); 00340 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); 00341 checkGLcall("glTexEnvi"); 00342 00343 /* Draw a quad */ 00344 glBegin(GL_TRIANGLE_STRIP); 00345 glTexCoord3fv(info.coords[0]); 00346 glVertex2i(dst_rect->left, dst_rect->top); 00347 00348 glTexCoord3fv(info.coords[1]); 00349 glVertex2i(dst_rect->right, dst_rect->top); 00350 00351 glTexCoord3fv(info.coords[2]); 00352 glVertex2i(dst_rect->left, dst_rect->bottom); 00353 00354 glTexCoord3fv(info.coords[3]); 00355 glVertex2i(dst_rect->right, dst_rect->bottom); 00356 glEnd(); 00357 00358 /* Unbind the texture */ 00359 context_bind_texture(context, info.bind_target, 0); 00360 00361 /* We changed the filtering settings on the texture. Inform the 00362 * container about this to get the filters reset properly next draw. */ 00363 if (src_surface->container.type == WINED3D_CONTAINER_TEXTURE) 00364 { 00365 struct wined3d_texture *texture = src_surface->container.u.texture; 00366 texture->texture_rgb.states[WINED3DTEXSTA_MAGFILTER] = WINED3D_TEXF_POINT; 00367 texture->texture_rgb.states[WINED3DTEXSTA_MINFILTER] = WINED3D_TEXF_POINT; 00368 texture->texture_rgb.states[WINED3DTEXSTA_MIPFILTER] = WINED3D_TEXF_NONE; 00369 texture->texture_rgb.states[WINED3DTEXSTA_SRGBTEXTURE] = FALSE; 00370 } 00371 } 00372 00373 static HRESULT surface_create_dib_section(struct wined3d_surface *surface) 00374 { 00375 const struct wined3d_format *format = surface->resource.format; 00376 SYSTEM_INFO sysInfo; 00377 BITMAPINFO *b_info; 00378 int extraline = 0; 00379 DWORD *masks; 00380 UINT usage; 00381 HDC dc; 00382 00383 TRACE("surface %p.\n", surface); 00384 00385 if (!(format->flags & WINED3DFMT_FLAG_GETDC)) 00386 { 00387 WARN("Cannot use GetDC on a %s surface.\n", debug_d3dformat(format->id)); 00388 return WINED3DERR_INVALIDCALL; 00389 } 00390 00391 switch (format->byte_count) 00392 { 00393 case 2: 00394 case 4: 00395 /* Allocate extra space to store the RGB bit masks. */ 00396 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD)); 00397 break; 00398 00399 case 3: 00400 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER)); 00401 break; 00402 00403 default: 00404 /* Allocate extra space for a palette. */ 00405 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 00406 sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << (format->byte_count * 8))); 00407 break; 00408 } 00409 00410 if (!b_info) 00411 return E_OUTOFMEMORY; 00412 00413 /* Some applications access the surface in via DWORDs, and do not take 00414 * the necessary care at the end of the surface. So we need at least 00415 * 4 extra bytes at the end of the surface. Check against the page size, 00416 * if the last page used for the surface has at least 4 spare bytes we're 00417 * safe, otherwise add an extra line to the DIB section. */ 00418 GetSystemInfo(&sysInfo); 00419 if( ((surface->resource.size + 3) % sysInfo.dwPageSize) < 4) 00420 { 00421 extraline = 1; 00422 TRACE("Adding an extra line to the DIB section.\n"); 00423 } 00424 00425 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 00426 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */ 00427 b_info->bmiHeader.biWidth = wined3d_surface_get_pitch(surface) / format->byte_count; 00428 b_info->bmiHeader.biHeight = 0 - surface->resource.height - extraline; 00429 b_info->bmiHeader.biSizeImage = (surface->resource.height + extraline) 00430 * wined3d_surface_get_pitch(surface); 00431 b_info->bmiHeader.biPlanes = 1; 00432 b_info->bmiHeader.biBitCount = format->byte_count * 8; 00433 00434 b_info->bmiHeader.biXPelsPerMeter = 0; 00435 b_info->bmiHeader.biYPelsPerMeter = 0; 00436 b_info->bmiHeader.biClrUsed = 0; 00437 b_info->bmiHeader.biClrImportant = 0; 00438 00439 /* Get the bit masks */ 00440 masks = (DWORD *)b_info->bmiColors; 00441 switch (surface->resource.format->id) 00442 { 00443 case WINED3DFMT_B8G8R8_UNORM: 00444 usage = DIB_RGB_COLORS; 00445 b_info->bmiHeader.biCompression = BI_RGB; 00446 break; 00447 00448 case WINED3DFMT_B5G5R5X1_UNORM: 00449 case WINED3DFMT_B5G5R5A1_UNORM: 00450 case WINED3DFMT_B4G4R4A4_UNORM: 00451 case WINED3DFMT_B4G4R4X4_UNORM: 00452 case WINED3DFMT_B2G3R3_UNORM: 00453 case WINED3DFMT_B2G3R3A8_UNORM: 00454 case WINED3DFMT_R10G10B10A2_UNORM: 00455 case WINED3DFMT_R8G8B8A8_UNORM: 00456 case WINED3DFMT_R8G8B8X8_UNORM: 00457 case WINED3DFMT_B10G10R10A2_UNORM: 00458 case WINED3DFMT_B5G6R5_UNORM: 00459 case WINED3DFMT_R16G16B16A16_UNORM: 00460 usage = 0; 00461 b_info->bmiHeader.biCompression = BI_BITFIELDS; 00462 masks[0] = format->red_mask; 00463 masks[1] = format->green_mask; 00464 masks[2] = format->blue_mask; 00465 break; 00466 00467 default: 00468 /* Don't know palette */ 00469 b_info->bmiHeader.biCompression = BI_RGB; 00470 usage = 0; 00471 break; 00472 } 00473 00474 if (!(dc = GetDC(0))) 00475 { 00476 HeapFree(GetProcessHeap(), 0, b_info); 00477 return HRESULT_FROM_WIN32(GetLastError()); 00478 } 00479 00480 TRACE("Creating a DIB section with size %dx%dx%d, size=%d.\n", 00481 b_info->bmiHeader.biWidth, b_info->bmiHeader.biHeight, 00482 b_info->bmiHeader.biBitCount, b_info->bmiHeader.biSizeImage); 00483 surface->dib.DIBsection = CreateDIBSection(dc, b_info, usage, &surface->dib.bitmap_data, 0, 0); 00484 ReleaseDC(0, dc); 00485 00486 if (!surface->dib.DIBsection) 00487 { 00488 ERR("Failed to create DIB section.\n"); 00489 HeapFree(GetProcessHeap(), 0, b_info); 00490 return HRESULT_FROM_WIN32(GetLastError()); 00491 } 00492 00493 TRACE("DIBSection at %p.\n", surface->dib.bitmap_data); 00494 /* Copy the existing surface to the dib section. */ 00495 if (surface->resource.allocatedMemory) 00496 { 00497 memcpy(surface->dib.bitmap_data, surface->resource.allocatedMemory, 00498 surface->resource.height * wined3d_surface_get_pitch(surface)); 00499 } 00500 else 00501 { 00502 /* This is to make maps read the GL texture although memory is allocated. */ 00503 surface->flags &= ~SFLAG_INSYSMEM; 00504 } 00505 surface->dib.bitmap_size = b_info->bmiHeader.biSizeImage; 00506 00507 HeapFree(GetProcessHeap(), 0, b_info); 00508 00509 /* Now allocate a DC. */ 00510 surface->hDC = CreateCompatibleDC(0); 00511 SelectObject(surface->hDC, surface->dib.DIBsection); 00512 TRACE("Using wined3d palette %p.\n", surface->palette); 00513 SelectPalette(surface->hDC, surface->palette ? surface->palette->hpal : 0, FALSE); 00514 00515 surface->flags |= SFLAG_DIBSECTION; 00516 00517 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory); 00518 surface->resource.heapMemory = NULL; 00519 00520 return WINED3D_OK; 00521 } 00522 00523 static BOOL surface_need_pbo(const struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info) 00524 { 00525 if (surface->resource.pool == WINED3D_POOL_SYSTEM_MEM) 00526 return FALSE; 00527 if (!(surface->flags & SFLAG_DYNLOCK)) 00528 return FALSE; 00529 if (surface->flags & (SFLAG_CONVERTED | SFLAG_NONPOW2 | SFLAG_PIN_SYSMEM)) 00530 return FALSE; 00531 if (!gl_info->supported[ARB_PIXEL_BUFFER_OBJECT]) 00532 return FALSE; 00533 00534 return TRUE; 00535 } 00536 00537 static void surface_load_pbo(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info) 00538 { 00539 struct wined3d_context *context; 00540 GLenum error; 00541 00542 context = context_acquire(surface->resource.device, NULL); 00543 ENTER_GL(); 00544 00545 GL_EXTCALL(glGenBuffersARB(1, &surface->pbo)); 00546 error = glGetError(); 00547 if (!surface->pbo || error != GL_NO_ERROR) 00548 ERR("Failed to create a PBO with error %s (%#x).\n", debug_glerror(error), error); 00549 00550 TRACE("Binding PBO %u.\n", surface->pbo); 00551 00552 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo)); 00553 checkGLcall("glBindBufferARB"); 00554 00555 GL_EXTCALL(glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->resource.size + 4, 00556 surface->resource.allocatedMemory, GL_STREAM_DRAW_ARB)); 00557 checkGLcall("glBufferDataARB"); 00558 00559 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0)); 00560 checkGLcall("glBindBufferARB"); 00561 00562 /* We don't need the system memory anymore and we can't even use it for PBOs. */ 00563 if (!(surface->flags & SFLAG_CLIENT)) 00564 { 00565 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory); 00566 surface->resource.heapMemory = NULL; 00567 } 00568 surface->resource.allocatedMemory = NULL; 00569 surface->flags |= SFLAG_PBO; 00570 LEAVE_GL(); 00571 context_release(context); 00572 } 00573 00574 static void surface_prepare_system_memory(struct wined3d_surface *surface) 00575 { 00576 const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info; 00577 00578 TRACE("surface %p.\n", surface); 00579 00580 if (!(surface->flags & SFLAG_PBO) && surface_need_pbo(surface, gl_info)) 00581 surface_load_pbo(surface, gl_info); 00582 else if (!(surface->resource.allocatedMemory || surface->flags & SFLAG_PBO)) 00583 { 00584 /* Whatever surface we have, make sure that there is memory allocated 00585 * for the downloaded copy, or a PBO to map. */ 00586 if (!surface->resource.heapMemory) 00587 surface->resource.heapMemory = HeapAlloc(GetProcessHeap(), 0, surface->resource.size + RESOURCE_ALIGNMENT); 00588 00589 surface->resource.allocatedMemory = (BYTE *)(((ULONG_PTR)surface->resource.heapMemory 00590 + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1)); 00591 00592 if (surface->flags & SFLAG_INSYSMEM) 00593 ERR("Surface without memory or PBO has SFLAG_INSYSMEM set.\n"); 00594 } 00595 } 00596 00597 static void surface_evict_sysmem(struct wined3d_surface *surface) 00598 { 00599 if (surface->flags & SFLAG_DONOTFREE) 00600 return; 00601 00602 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory); 00603 surface->resource.allocatedMemory = NULL; 00604 surface->resource.heapMemory = NULL; 00605 surface_modify_location(surface, SFLAG_INSYSMEM, FALSE); 00606 } 00607 00608 /* Context activation is done by the caller. */ 00609 static void surface_bind_and_dirtify(struct wined3d_surface *surface, 00610 struct wined3d_context *context, BOOL srgb) 00611 { 00612 struct wined3d_device *device = surface->resource.device; 00613 DWORD active_sampler; 00614 00615 /* We don't need a specific texture unit, but after binding the texture 00616 * the current unit is dirty. Read the unit back instead of switching to 00617 * 0, this avoids messing around with the state manager's GL states. The 00618 * current texture unit should always be a valid one. 00619 * 00620 * To be more specific, this is tricky because we can implicitly be 00621 * called from sampler() in state.c. This means we can't touch anything 00622 * other than whatever happens to be the currently active texture, or we 00623 * would risk marking already applied sampler states dirty again. */ 00624 active_sampler = device->rev_tex_unit_map[context->active_texture]; 00625 00626 if (active_sampler != WINED3D_UNMAPPED_STAGE) 00627 device_invalidate_state(device, STATE_SAMPLER(active_sampler)); 00628 surface_bind(surface, context, srgb); 00629 } 00630 00631 static void surface_force_reload(struct wined3d_surface *surface) 00632 { 00633 surface->flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED); 00634 } 00635 00636 static void surface_release_client_storage(struct wined3d_surface *surface) 00637 { 00638 struct wined3d_context *context = context_acquire(surface->resource.device, NULL); 00639 00640 ENTER_GL(); 00641 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE); 00642 if (surface->texture_name) 00643 { 00644 surface_bind_and_dirtify(surface, context, FALSE); 00645 glTexImage2D(surface->texture_target, surface->texture_level, 00646 GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); 00647 } 00648 if (surface->texture_name_srgb) 00649 { 00650 surface_bind_and_dirtify(surface, context, TRUE); 00651 glTexImage2D(surface->texture_target, surface->texture_level, 00652 GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); 00653 } 00654 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE); 00655 LEAVE_GL(); 00656 00657 context_release(context); 00658 00659 surface_modify_location(surface, SFLAG_INSRGBTEX, FALSE); 00660 surface_modify_location(surface, SFLAG_INTEXTURE, FALSE); 00661 surface_force_reload(surface); 00662 } 00663 00664 static HRESULT surface_private_setup(struct wined3d_surface *surface) 00665 { 00666 /* TODO: Check against the maximum texture sizes supported by the video card. */ 00667 const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info; 00668 unsigned int pow2Width, pow2Height; 00669 00670 TRACE("surface %p.\n", surface); 00671 00672 surface->texture_name = 0; 00673 surface->texture_target = GL_TEXTURE_2D; 00674 00675 /* Non-power2 support */ 00676 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT]) 00677 { 00678 pow2Width = surface->resource.width; 00679 pow2Height = surface->resource.height; 00680 } 00681 else 00682 { 00683 /* Find the nearest pow2 match */ 00684 pow2Width = pow2Height = 1; 00685 while (pow2Width < surface->resource.width) 00686 pow2Width <<= 1; 00687 while (pow2Height < surface->resource.height) 00688 pow2Height <<= 1; 00689 } 00690 surface->pow2Width = pow2Width; 00691 surface->pow2Height = pow2Height; 00692 00693 if (pow2Width > surface->resource.width || pow2Height > surface->resource.height) 00694 { 00695 /* TODO: Add support for non power two compressed textures. */ 00696 if (surface->resource.format->flags & WINED3DFMT_FLAG_COMPRESSED) 00697 { 00698 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n", 00699 surface, surface->resource.width, surface->resource.height); 00700 return WINED3DERR_NOTAVAILABLE; 00701 } 00702 } 00703 00704 if (pow2Width != surface->resource.width 00705 || pow2Height != surface->resource.height) 00706 { 00707 surface->flags |= SFLAG_NONPOW2; 00708 } 00709 00710 if ((surface->pow2Width > gl_info->limits.texture_size || surface->pow2Height > gl_info->limits.texture_size) 00711 && !(surface->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL))) 00712 { 00713 /* One of three options: 00714 * 1: Do the same as we do with NPOT and scale the texture, (any 00715 * texture ops would require the texture to be scaled which is 00716 * potentially slow) 00717 * 2: Set the texture to the maximum size (bad idea). 00718 * 3: WARN and return WINED3DERR_NOTAVAILABLE; 00719 * 4: Create the surface, but allow it to be used only for DirectDraw 00720 * Blts. Some apps (e.g. Swat 3) create textures with a Height of 00721 * 16 and a Width > 3000 and blt 16x16 letter areas from them to 00722 * the render target. */ 00723 if (surface->resource.pool == WINED3D_POOL_DEFAULT || surface->resource.pool == WINED3D_POOL_MANAGED) 00724 { 00725 WARN("Unable to allocate a surface which exceeds the maximum OpenGL texture size.\n"); 00726 return WINED3DERR_NOTAVAILABLE; 00727 } 00728 00729 /* We should never use this surface in combination with OpenGL! */ 00730 TRACE("Creating an oversized surface: %ux%u.\n", 00731 surface->pow2Width, surface->pow2Height); 00732 } 00733 else 00734 { 00735 /* Don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 00736 * and EXT_PALETTED_TEXTURE is used in combination with texture 00737 * uploads (RTL_READTEX/RTL_TEXTEX). The reason is that 00738 * EXT_PALETTED_TEXTURE doesn't work in combination with 00739 * ARB_TEXTURE_RECTANGLE. */ 00740 if (surface->flags & SFLAG_NONPOW2 && gl_info->supported[ARB_TEXTURE_RECTANGLE] 00741 && !(surface->resource.format->id == WINED3DFMT_P8_UINT 00742 && gl_info->supported[EXT_PALETTED_TEXTURE] 00743 && wined3d_settings.rendertargetlock_mode == RTL_READTEX)) 00744 { 00745 surface->texture_target = GL_TEXTURE_RECTANGLE_ARB; 00746 surface->pow2Width = surface->resource.width; 00747 surface->pow2Height = surface->resource.height; 00748 surface->flags &= ~(SFLAG_NONPOW2 | SFLAG_NORMCOORD); 00749 } 00750 } 00751 00752 switch (wined3d_settings.offscreen_rendering_mode) 00753 { 00754 case ORM_FBO: 00755 surface->get_drawable_size = get_drawable_size_fbo; 00756 break; 00757 00758 case ORM_BACKBUFFER: 00759 surface->get_drawable_size = get_drawable_size_backbuffer; 00760 break; 00761 00762 default: 00763 ERR("Unhandled offscreen rendering mode %#x.\n", wined3d_settings.offscreen_rendering_mode); 00764 return WINED3DERR_INVALIDCALL; 00765 } 00766 00767 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) 00768 surface->flags |= SFLAG_LOST; 00769 00770 return WINED3D_OK; 00771 } 00772 00773 static void surface_realize_palette(struct wined3d_surface *surface) 00774 { 00775 struct wined3d_palette *palette = surface->palette; 00776 00777 TRACE("surface %p.\n", surface); 00778 00779 if (!palette) return; 00780 00781 if (surface->resource.format->id == WINED3DFMT_P8_UINT 00782 || surface->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM) 00783 { 00784 if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET) 00785 { 00786 /* Make sure the texture is up to date. This call doesn't do 00787 * anything if the texture is already up to date. */ 00788 surface_load_location(surface, SFLAG_INTEXTURE, NULL); 00789 00790 /* We want to force a palette refresh, so mark the drawable as not being up to date */ 00791 if (!surface_is_offscreen(surface)) 00792 surface_modify_location(surface, SFLAG_INDRAWABLE, FALSE); 00793 } 00794 else 00795 { 00796 if (!(surface->flags & SFLAG_INSYSMEM)) 00797 { 00798 TRACE("Palette changed with surface that does not have an up to date system memory copy.\n"); 00799 surface_load_location(surface, SFLAG_INSYSMEM, NULL); 00800 } 00801 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE); 00802 } 00803 } 00804 00805 if (surface->flags & SFLAG_DIBSECTION) 00806 { 00807 RGBQUAD col[256]; 00808 unsigned int i; 00809 00810 TRACE("Updating the DC's palette.\n"); 00811 00812 for (i = 0; i < 256; ++i) 00813 { 00814 col[i].rgbRed = palette->palents[i].peRed; 00815 col[i].rgbGreen = palette->palents[i].peGreen; 00816 col[i].rgbBlue = palette->palents[i].peBlue; 00817 col[i].rgbReserved = 0; 00818 } 00819 SetDIBColorTable(surface->hDC, 0, 256, col); 00820 } 00821 00822 /* Propagate the changes to the drawable when we have a palette. */ 00823 if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET) 00824 surface_load_location(surface, surface->draw_binding, NULL); 00825 } 00826 00827 static HRESULT surface_draw_overlay(struct wined3d_surface *surface) 00828 { 00829 HRESULT hr; 00830 00831 /* If there's no destination surface there is nothing to do. */ 00832 if (!surface->overlay_dest) 00833 return WINED3D_OK; 00834 00835 /* Blt calls ModifyLocation on the dest surface, which in turn calls 00836 * DrawOverlay to update the overlay. Prevent an endless recursion. */ 00837 if (surface->overlay_dest->flags & SFLAG_INOVERLAYDRAW) 00838 return WINED3D_OK; 00839 00840 surface->overlay_dest->flags |= SFLAG_INOVERLAYDRAW; 00841 hr = wined3d_surface_blt(surface->overlay_dest, &surface->overlay_destrect, surface, 00842 &surface->overlay_srcrect, WINEDDBLT_WAIT, NULL, WINED3D_TEXF_LINEAR); 00843 surface->overlay_dest->flags &= ~SFLAG_INOVERLAYDRAW; 00844 00845 return hr; 00846 } 00847 00848 static void surface_map(struct wined3d_surface *surface, const RECT *rect, DWORD flags) 00849 { 00850 struct wined3d_device *device = surface->resource.device; 00851 const RECT *pass_rect = rect; 00852 00853 TRACE("surface %p, rect %s, flags %#x.\n", 00854 surface, wine_dbgstr_rect(rect), flags); 00855 00856 if (flags & WINED3DLOCK_DISCARD) 00857 { 00858 TRACE("WINED3DLOCK_DISCARD flag passed, marking SYSMEM as up to date.\n"); 00859 surface_prepare_system_memory(surface); 00860 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE); 00861 } 00862 else 00863 { 00864 /* surface_load_location() does not check if the rectangle specifies 00865 * the full surface. Most callers don't need that, so do it here. */ 00866 if (rect && !rect->top && !rect->left 00867 && rect->right == surface->resource.width 00868 && rect->bottom == surface->resource.height) 00869 pass_rect = NULL; 00870 surface_load_location(surface, SFLAG_INSYSMEM, pass_rect); 00871 } 00872 00873 if (surface->flags & SFLAG_PBO) 00874 { 00875 const struct wined3d_gl_info *gl_info; 00876 struct wined3d_context *context; 00877 00878 context = context_acquire(device, NULL); 00879 gl_info = context->gl_info; 00880 00881 ENTER_GL(); 00882 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo)); 00883 checkGLcall("glBindBufferARB"); 00884 00885 /* This shouldn't happen but could occur if some other function 00886 * didn't handle the PBO properly. */ 00887 if (surface->resource.allocatedMemory) 00888 ERR("The surface already has PBO memory allocated.\n"); 00889 00890 surface->resource.allocatedMemory = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB)); 00891 checkGLcall("glMapBufferARB"); 00892 00893 /* Make sure the PBO isn't set anymore in order not to break non-PBO 00894 * calls. */ 00895 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0)); 00896 checkGLcall("glBindBufferARB"); 00897 00898 LEAVE_GL(); 00899 context_release(context); 00900 } 00901 00902 if (!(flags & (WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY))) 00903 { 00904 if (!rect) 00905 surface_add_dirty_rect(surface, NULL); 00906 else 00907 { 00908 struct wined3d_box b; 00909 00910 b.left = rect->left; 00911 b.top = rect->top; 00912 b.right = rect->right; 00913 b.bottom = rect->bottom; 00914 b.front = 0; 00915 b.back = 1; 00916 surface_add_dirty_rect(surface, &b); 00917 } 00918 } 00919 } 00920 00921 static void surface_unmap(struct wined3d_surface *surface) 00922 { 00923 struct wined3d_device *device = surface->resource.device; 00924 BOOL fullsurface; 00925 00926 TRACE("surface %p.\n", surface); 00927 00928 memset(&surface->lockedRect, 0, sizeof(surface->lockedRect)); 00929 00930 if (surface->flags & SFLAG_PBO) 00931 { 00932 const struct wined3d_gl_info *gl_info; 00933 struct wined3d_context *context; 00934 00935 TRACE("Freeing PBO memory.\n"); 00936 00937 context = context_acquire(device, NULL); 00938 gl_info = context->gl_info; 00939 00940 ENTER_GL(); 00941 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo)); 00942 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB)); 00943 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0)); 00944 checkGLcall("glUnmapBufferARB"); 00945 LEAVE_GL(); 00946 context_release(context); 00947 00948 surface->resource.allocatedMemory = NULL; 00949 } 00950 00951 TRACE("dirtyfied %u.\n", surface->flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE) ? 0 : 1); 00952 00953 if (surface->flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE)) 00954 { 00955 TRACE("Not dirtified, nothing to do.\n"); 00956 goto done; 00957 } 00958 00959 if (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN 00960 || (device->fb.render_targets && surface == device->fb.render_targets[0])) 00961 { 00962 if (!surface->dirtyRect.left && !surface->dirtyRect.top 00963 && surface->dirtyRect.right == surface->resource.width 00964 && surface->dirtyRect.bottom == surface->resource.height) 00965 { 00966 fullsurface = TRUE; 00967 } 00968 else 00969 { 00970 /* TODO: Proper partial rectangle tracking. */ 00971 fullsurface = FALSE; 00972 surface->flags |= SFLAG_INSYSMEM; 00973 } 00974 00975 surface_load_location(surface, surface->draw_binding, fullsurface ? NULL : &surface->dirtyRect); 00976 00977 /* Partial rectangle tracking is not commonly implemented, it is only 00978 * done for render targets. INSYSMEM was set before to tell 00979 * surface_load_location() where to read the rectangle from. 00980 * Indrawable is set because all modifications from the partial 00981 * sysmem copy are written back to the drawable, thus the surface is 00982 * merged again in the drawable. The sysmem copy is not fully up to 00983 * date because only a subrectangle was read in Map(). */ 00984 if (!fullsurface) 00985 { 00986 surface_modify_location(surface, surface->draw_binding, TRUE); 00987 surface_evict_sysmem(surface); 00988 } 00989 00990 surface->dirtyRect.left = surface->resource.width; 00991 surface->dirtyRect.top = surface->resource.height; 00992 surface->dirtyRect.right = 0; 00993 surface->dirtyRect.bottom = 0; 00994 } 00995 else if (surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)) 00996 { 00997 FIXME("Depth / stencil buffer locking is not implemented.\n"); 00998 } 00999 01000 done: 01001 /* Overlays have to be redrawn manually after changes with the GL implementation */ 01002 if (surface->overlay_dest) 01003 surface_draw_overlay(surface); 01004 } 01005 01006 static BOOL surface_is_full_rect(const struct wined3d_surface *surface, const RECT *r) 01007 { 01008 if ((r->left && r->right) || abs(r->right - r->left) != surface->resource.width) 01009 return FALSE; 01010 if ((r->top && r->bottom) || abs(r->bottom - r->top) != surface->resource.height) 01011 return FALSE; 01012 return TRUE; 01013 } 01014 01015 static void wined3d_surface_depth_blt_fbo(const struct wined3d_device *device, struct wined3d_surface *src_surface, 01016 const RECT *src_rect, struct wined3d_surface *dst_surface, const RECT *dst_rect) 01017 { 01018 const struct wined3d_gl_info *gl_info; 01019 struct wined3d_context *context; 01020 DWORD src_mask, dst_mask; 01021 GLbitfield gl_mask; 01022 01023 TRACE("device %p, src_surface %p, src_rect %s, dst_surface %p, dst_rect %s.\n", 01024 device, src_surface, wine_dbgstr_rect(src_rect), 01025 dst_surface, wine_dbgstr_rect(dst_rect)); 01026 01027 src_mask = src_surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL); 01028 dst_mask = dst_surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL); 01029 01030 if (src_mask != dst_mask) 01031 { 01032 ERR("Incompatible formats %s and %s.\n", 01033 debug_d3dformat(src_surface->resource.format->id), 01034 debug_d3dformat(dst_surface->resource.format->id)); 01035 return; 01036 } 01037 01038 if (!src_mask) 01039 { 01040 ERR("Not a depth / stencil format: %s.\n", 01041 debug_d3dformat(src_surface->resource.format->id)); 01042 return; 01043 } 01044 01045 gl_mask = 0; 01046 if (src_mask & WINED3DFMT_FLAG_DEPTH) 01047 gl_mask |= GL_DEPTH_BUFFER_BIT; 01048 if (src_mask & WINED3DFMT_FLAG_STENCIL) 01049 gl_mask |= GL_STENCIL_BUFFER_BIT; 01050 01051 /* Make sure the locations are up-to-date. Loading the destination 01052 * surface isn't required if the entire surface is overwritten. */ 01053 surface_load_location(src_surface, SFLAG_INTEXTURE, NULL); 01054 if (!surface_is_full_rect(dst_surface, dst_rect)) 01055 surface_load_location(dst_surface, SFLAG_INTEXTURE, NULL); 01056 01057 context = context_acquire(device, NULL); 01058 if (!context->valid) 01059 { 01060 context_release(context); 01061 WARN("Invalid context, skipping blit.\n"); 01062 return; 01063 } 01064 01065 gl_info = context->gl_info; 01066 01067 ENTER_GL(); 01068 01069 context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, NULL, src_surface, SFLAG_INTEXTURE); 01070 glReadBuffer(GL_NONE); 01071 checkGLcall("glReadBuffer()"); 01072 context_check_fbo_status(context, GL_READ_FRAMEBUFFER); 01073 01074 context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, NULL, dst_surface, SFLAG_INTEXTURE); 01075 context_set_draw_buffer(context, GL_NONE); 01076 context_check_fbo_status(context, GL_DRAW_FRAMEBUFFER); 01077 01078 if (gl_mask & GL_DEPTH_BUFFER_BIT) 01079 { 01080 glDepthMask(GL_TRUE); 01081 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ZWRITEENABLE)); 01082 } 01083 if (gl_mask & GL_STENCIL_BUFFER_BIT) 01084 { 01085 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE]) 01086 { 01087 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT); 01088 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_TWOSIDEDSTENCILMODE)); 01089 } 01090 glStencilMask(~0U); 01091 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK)); 01092 } 01093 01094 glDisable(GL_SCISSOR_TEST); 01095 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE)); 01096 01097 gl_info->fbo_ops.glBlitFramebuffer(src_rect->left, src_rect->top, src_rect->right, src_rect->bottom, 01098 dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, gl_mask, GL_NEAREST); 01099 checkGLcall("glBlitFramebuffer()"); 01100 01101 LEAVE_GL(); 01102 01103 if (wined3d_settings.strict_draw_ordering) 01104 wglFlush(); /* Flush to ensure ordering across contexts. */ 01105 01106 context_release(context); 01107 } 01108 01109 /* Blit between surface locations. Onscreen on different swapchains is not supported. 01110 * Depth / stencil is not supported. */ 01111 static void surface_blt_fbo(const struct wined3d_device *device, enum wined3d_texture_filter_type filter, 01112 struct wined3d_surface *src_surface, DWORD src_location, const RECT *src_rect_in, 01113 struct wined3d_surface *dst_surface, DWORD dst_location, const RECT *dst_rect_in) 01114 { 01115 const struct wined3d_gl_info *gl_info; 01116 struct wined3d_context *context; 01117 RECT src_rect, dst_rect; 01118 GLenum gl_filter; 01119 GLenum buffer; 01120 01121 TRACE("device %p, filter %s,\n", device, debug_d3dtexturefiltertype(filter)); 01122 TRACE("src_surface %p, src_location %s, src_rect %s,\n", 01123 src_surface, debug_surflocation(src_location), wine_dbgstr_rect(src_rect_in)); 01124 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n", 01125 dst_surface, debug_surflocation(dst_location), wine_dbgstr_rect(dst_rect_in)); 01126 01127 src_rect = *src_rect_in; 01128 dst_rect = *dst_rect_in; 01129 01130 switch (filter) 01131 { 01132 case WINED3D_TEXF_LINEAR: 01133 gl_filter = GL_LINEAR; 01134 break; 01135 01136 default: 01137 FIXME("Unsupported filter mode %s (%#x).\n", debug_d3dtexturefiltertype(filter), filter); 01138 case WINED3D_TEXF_NONE: 01139 case WINED3D_TEXF_POINT: 01140 gl_filter = GL_NEAREST; 01141 break; 01142 } 01143 01144 /* Resolve the source surface first if needed. */ 01145 if (src_location == SFLAG_INRB_MULTISAMPLE 01146 && (src_surface->resource.format->id != dst_surface->resource.format->id 01147 || abs(src_rect.bottom - src_rect.top) != abs(dst_rect.bottom - dst_rect.top) 01148 || abs(src_rect.right - src_rect.left) != abs(dst_rect.right - dst_rect.left))) 01149 src_location = SFLAG_INRB_RESOLVED; 01150 01151 /* Make sure the locations are up-to-date. Loading the destination 01152 * surface isn't required if the entire surface is overwritten. (And is 01153 * in fact harmful if we're being called by surface_load_location() with 01154 * the purpose of loading the destination surface.) */ 01155 surface_load_location(src_surface, src_location, NULL); 01156 if (!surface_is_full_rect(dst_surface, &dst_rect)) 01157 surface_load_location(dst_surface, dst_location, NULL); 01158 01159 if (src_location == SFLAG_INDRAWABLE) context = context_acquire(device, src_surface); 01160 else if (dst_location == SFLAG_INDRAWABLE) context = context_acquire(device, dst_surface); 01161 else context = context_acquire(device, NULL); 01162 01163 if (!context->valid) 01164 { 01165 context_release(context); 01166 WARN("Invalid context, skipping blit.\n"); 01167 return; 01168 } 01169 01170 gl_info = context->gl_info; 01171 01172 if (src_location == SFLAG_INDRAWABLE) 01173 { 01174 TRACE("Source surface %p is onscreen.\n", src_surface); 01175 buffer = surface_get_gl_buffer(src_surface); 01176 surface_translate_drawable_coords(src_surface, context->win_handle, &src_rect); 01177 } 01178 else 01179 { 01180 TRACE("Source surface %p is offscreen.\n", src_surface); 01181 buffer = GL_COLOR_ATTACHMENT0; 01182 } 01183 01184 ENTER_GL(); 01185 context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, src_surface, NULL, src_location); 01186 glReadBuffer(buffer); 01187 checkGLcall("glReadBuffer()"); 01188 context_check_fbo_status(context, GL_READ_FRAMEBUFFER); 01189 LEAVE_GL(); 01190 01191 if (dst_location == SFLAG_INDRAWABLE) 01192 { 01193 TRACE("Destination surface %p is onscreen.\n", dst_surface); 01194 buffer = surface_get_gl_buffer(dst_surface); 01195 surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect); 01196 } 01197 else 01198 { 01199 TRACE("Destination surface %p is offscreen.\n", dst_surface); 01200 buffer = GL_COLOR_ATTACHMENT0; 01201 } 01202 01203 ENTER_GL(); 01204 context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, dst_surface, NULL, dst_location); 01205 context_set_draw_buffer(context, buffer); 01206 context_check_fbo_status(context, GL_DRAW_FRAMEBUFFER); 01207 context_invalidate_state(context, STATE_FRAMEBUFFER); 01208 01209 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); 01210 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE)); 01211 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE1)); 01212 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE2)); 01213 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE3)); 01214 01215 glDisable(GL_SCISSOR_TEST); 01216 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE)); 01217 01218 gl_info->fbo_ops.glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom, 01219 dst_rect.left, dst_rect.top, dst_rect.right, dst_rect.bottom, GL_COLOR_BUFFER_BIT, gl_filter); 01220 checkGLcall("glBlitFramebuffer()"); 01221 01222 LEAVE_GL(); 01223 01224 if (wined3d_settings.strict_draw_ordering 01225 || (dst_location == SFLAG_INDRAWABLE 01226 && dst_surface->container.u.swapchain->front_buffer == dst_surface)) 01227 wglFlush(); 01228 01229 context_release(context); 01230 } 01231 01232 static BOOL fbo_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op, 01233 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format, 01234 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format) 01235 { 01236 if ((wined3d_settings.offscreen_rendering_mode != ORM_FBO) || !gl_info->fbo_ops.glBlitFramebuffer) 01237 return FALSE; 01238 01239 /* Source and/or destination need to be on the GL side */ 01240 if (src_pool == WINED3D_POOL_SYSTEM_MEM || dst_pool == WINED3D_POOL_SYSTEM_MEM) 01241 return FALSE; 01242 01243 switch (blit_op) 01244 { 01245 case WINED3D_BLIT_OP_COLOR_BLIT: 01246 if (!((src_format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE) || (src_usage & WINED3DUSAGE_RENDERTARGET))) 01247 return FALSE; 01248 if (!((dst_format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE) || (dst_usage & WINED3DUSAGE_RENDERTARGET))) 01249 return FALSE; 01250 break; 01251 01252 case WINED3D_BLIT_OP_DEPTH_BLIT: 01253 if (!(src_format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL))) 01254 return FALSE; 01255 if (!(dst_format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL))) 01256 return FALSE; 01257 break; 01258 01259 default: 01260 return FALSE; 01261 } 01262 01263 if (!(src_format->id == dst_format->id 01264 || (is_identity_fixup(src_format->color_fixup) 01265 && is_identity_fixup(dst_format->color_fixup)))) 01266 return FALSE; 01267 01268 return TRUE; 01269 } 01270 01271 /* This function checks if the primary render target uses the 8bit paletted format. */ 01272 static BOOL primary_render_target_is_p8(const struct wined3d_device *device) 01273 { 01274 if (device->fb.render_targets && device->fb.render_targets[0]) 01275 { 01276 const struct wined3d_surface *render_target = device->fb.render_targets[0]; 01277 if ((render_target->resource.usage & WINED3DUSAGE_RENDERTARGET) 01278 && (render_target->resource.format->id == WINED3DFMT_P8_UINT)) 01279 return TRUE; 01280 } 01281 return FALSE; 01282 } 01283 01284 static BOOL surface_convert_color_to_float(const struct wined3d_surface *surface, 01285 DWORD color, struct wined3d_color *float_color) 01286 { 01287 const struct wined3d_format *format = surface->resource.format; 01288 const struct wined3d_device *device = surface->resource.device; 01289 01290 switch (format->id) 01291 { 01292 case WINED3DFMT_P8_UINT: 01293 if (surface->palette) 01294 { 01295 float_color->r = surface->palette->palents[color].peRed / 255.0f; 01296 float_color->g = surface->palette->palents[color].peGreen / 255.0f; 01297 float_color->b = surface->palette->palents[color].peBlue / 255.0f; 01298 } 01299 else 01300 { 01301 float_color->r = 0.0f; 01302 float_color->g = 0.0f; 01303 float_color->b = 0.0f; 01304 } 01305 float_color->a = primary_render_target_is_p8(device) ? color / 255.0f : 1.0f; 01306 break; 01307 01308 case WINED3DFMT_B5G6R5_UNORM: 01309 float_color->r = ((color >> 11) & 0x1f) / 31.0f; 01310 float_color->g = ((color >> 5) & 0x3f) / 63.0f; 01311 float_color->b = (color & 0x1f) / 31.0f; 01312 float_color->a = 1.0f; 01313 break; 01314 01315 case WINED3DFMT_B8G8R8_UNORM: 01316 case WINED3DFMT_B8G8R8X8_UNORM: 01317 float_color->r = D3DCOLOR_R(color); 01318 float_color->g = D3DCOLOR_G(color); 01319 float_color->b = D3DCOLOR_B(color); 01320 float_color->a = 1.0f; 01321 break; 01322 01323 case WINED3DFMT_B8G8R8A8_UNORM: 01324 float_color->r = D3DCOLOR_R(color); 01325 float_color->g = D3DCOLOR_G(color); 01326 float_color->b = D3DCOLOR_B(color); 01327 float_color->a = D3DCOLOR_A(color); 01328 break; 01329 01330 default: 01331 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format->id)); 01332 return FALSE; 01333 } 01334 01335 return TRUE; 01336 } 01337 01338 static BOOL surface_convert_depth_to_float(const struct wined3d_surface *surface, DWORD depth, float *float_depth) 01339 { 01340 const struct wined3d_format *format = surface->resource.format; 01341 01342 switch (format->id) 01343 { 01344 case WINED3DFMT_S1_UINT_D15_UNORM: 01345 *float_depth = depth / (float)0x00007fff; 01346 break; 01347 01348 case WINED3DFMT_D16_UNORM: 01349 *float_depth = depth / (float)0x0000ffff; 01350 break; 01351 01352 case WINED3DFMT_D24_UNORM_S8_UINT: 01353 case WINED3DFMT_X8D24_UNORM: 01354 *float_depth = depth / (float)0x00ffffff; 01355 break; 01356 01357 case WINED3DFMT_D32_UNORM: 01358 *float_depth = depth / (float)0xffffffff; 01359 break; 01360 01361 default: 01362 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format->id)); 01363 return FALSE; 01364 } 01365 01366 return TRUE; 01367 } 01368 01369 /* Do not call while under the GL lock. */ 01370 static HRESULT wined3d_surface_depth_fill(struct wined3d_surface *surface, const RECT *rect, float depth) 01371 { 01372 const struct wined3d_resource *resource = &surface->resource; 01373 struct wined3d_device *device = resource->device; 01374 const struct blit_shader *blitter; 01375 01376 blitter = wined3d_select_blitter(&device->adapter->gl_info, WINED3D_BLIT_OP_DEPTH_FILL, 01377 NULL, 0, 0, NULL, rect, resource->usage, resource->pool, resource->format); 01378 if (!blitter) 01379 { 01380 FIXME("No blitter is capable of performing the requested depth fill operation.\n"); 01381 return WINED3DERR_INVALIDCALL; 01382 } 01383 01384 return blitter->depth_fill(device, surface, rect, depth); 01385 } 01386 01387 static HRESULT wined3d_surface_depth_blt(struct wined3d_surface *src_surface, const RECT *src_rect, 01388 struct wined3d_surface *dst_surface, const RECT *dst_rect) 01389 { 01390 struct wined3d_device *device = src_surface->resource.device; 01391 01392 if (!fbo_blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_DEPTH_BLIT, 01393 src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format, 01394 dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format)) 01395 return WINED3DERR_INVALIDCALL; 01396 01397 wined3d_surface_depth_blt_fbo(device, src_surface, src_rect, dst_surface, dst_rect); 01398 01399 surface_modify_ds_location(dst_surface, SFLAG_INTEXTURE, 01400 dst_surface->ds_current_size.cx, dst_surface->ds_current_size.cy); 01401 01402 return WINED3D_OK; 01403 } 01404 01405 /* Do not call while under the GL lock. */ 01406 HRESULT CDECL wined3d_surface_blt(struct wined3d_surface *dst_surface, const RECT *dst_rect_in, 01407 struct wined3d_surface *src_surface, const RECT *src_rect_in, DWORD flags, 01408 const WINEDDBLTFX *fx, enum wined3d_texture_filter_type filter) 01409 { 01410 struct wined3d_swapchain *src_swapchain, *dst_swapchain; 01411 struct wined3d_device *device = dst_surface->resource.device; 01412 DWORD src_ds_flags, dst_ds_flags; 01413 RECT src_rect, dst_rect; 01414 BOOL scale, convert; 01415 01416 static const DWORD simple_blit = WINEDDBLT_ASYNC 01417 | WINEDDBLT_COLORFILL 01418 | WINEDDBLT_WAIT 01419 | WINEDDBLT_DEPTHFILL 01420 | WINEDDBLT_DONOTWAIT; 01421 01422 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n", 01423 dst_surface, wine_dbgstr_rect(dst_rect_in), src_surface, wine_dbgstr_rect(src_rect_in), 01424 flags, fx, debug_d3dtexturefiltertype(filter)); 01425 TRACE("Usage is %s.\n", debug_d3dusage(dst_surface->resource.usage)); 01426 01427 if (fx) 01428 { 01429 TRACE("dwSize %#x.\n", fx->dwSize); 01430 TRACE("dwDDFX %#x.\n", fx->dwDDFX); 01431 TRACE("dwROP %#x.\n", fx->dwROP); 01432 TRACE("dwDDROP %#x.\n", fx->dwDDROP); 01433 TRACE("dwRotationAngle %#x.\n", fx->dwRotationAngle); 01434 TRACE("dwZBufferOpCode %#x.\n", fx->dwZBufferOpCode); 01435 TRACE("dwZBufferLow %#x.\n", fx->dwZBufferLow); 01436 TRACE("dwZBufferHigh %#x.\n", fx->dwZBufferHigh); 01437 TRACE("dwZBufferBaseDest %#x.\n", fx->dwZBufferBaseDest); 01438 TRACE("dwZDestConstBitDepth %#x.\n", fx->dwZDestConstBitDepth); 01439 TRACE("lpDDSZBufferDest %p.\n", fx->u1.lpDDSZBufferDest); 01440 TRACE("dwZSrcConstBitDepth %#x.\n", fx->dwZSrcConstBitDepth); 01441 TRACE("lpDDSZBufferSrc %p.\n", fx->u2.lpDDSZBufferSrc); 01442 TRACE("dwAlphaEdgeBlendBitDepth %#x.\n", fx->dwAlphaEdgeBlendBitDepth); 01443 TRACE("dwAlphaEdgeBlend %#x.\n", fx->dwAlphaEdgeBlend); 01444 TRACE("dwReserved %#x.\n", fx->dwReserved); 01445 TRACE("dwAlphaDestConstBitDepth %#x.\n", fx->dwAlphaDestConstBitDepth); 01446 TRACE("lpDDSAlphaDest %p.\n", fx->u3.lpDDSAlphaDest); 01447 TRACE("dwAlphaSrcConstBitDepth %#x.\n", fx->dwAlphaSrcConstBitDepth); 01448 TRACE("lpDDSAlphaSrc %p.\n", fx->u4.lpDDSAlphaSrc); 01449 TRACE("lpDDSPattern %p.\n", fx->u5.lpDDSPattern); 01450 TRACE("ddckDestColorkey {%#x, %#x}.\n", 01451 fx->ddckDestColorkey.color_space_low_value, 01452 fx->ddckDestColorkey.color_space_high_value); 01453 TRACE("ddckSrcColorkey {%#x, %#x}.\n", 01454 fx->ddckSrcColorkey.color_space_low_value, 01455 fx->ddckSrcColorkey.color_space_high_value); 01456 } 01457 01458 if ((dst_surface->flags & SFLAG_LOCKED) || (src_surface && (src_surface->flags & SFLAG_LOCKED))) 01459 { 01460 WARN("Surface is busy, returning WINEDDERR_SURFACEBUSY.\n"); 01461 return WINEDDERR_SURFACEBUSY; 01462 } 01463 01464 surface_get_rect(dst_surface, dst_rect_in, &dst_rect); 01465 01466 if (dst_rect.left >= dst_rect.right || dst_rect.top >= dst_rect.bottom 01467 || dst_rect.left > dst_surface->resource.width || dst_rect.left < 0 01468 || dst_rect.top > dst_surface->resource.height || dst_rect.top < 0 01469 || dst_rect.right > dst_surface->resource.width || dst_rect.right < 0 01470 || dst_rect.bottom > dst_surface->resource.height || dst_rect.bottom < 0) 01471 { 01472 WARN("The application gave us a bad destination rectangle.\n"); 01473 return WINEDDERR_INVALIDRECT; 01474 } 01475 01476 if (src_surface) 01477 { 01478 surface_get_rect(src_surface, src_rect_in, &src_rect); 01479 01480 if (src_rect.left >= src_rect.right || src_rect.top >= src_rect.bottom 01481 || src_rect.left > src_surface->resource.width || src_rect.left < 0 01482 || src_rect.top > src_surface->resource.height || src_rect.top < 0 01483 || src_rect.right > src_surface->resource.width || src_rect.right < 0 01484 || src_rect.bottom > src_surface->resource.height || src_rect.bottom < 0) 01485 { 01486 WARN("Application gave us bad source rectangle for Blt.\n"); 01487 return WINEDDERR_INVALIDRECT; 01488 } 01489 } 01490 else 01491 { 01492 memset(&src_rect, 0, sizeof(src_rect)); 01493 } 01494 01495 if (!fx || !(fx->dwDDFX)) 01496 flags &= ~WINEDDBLT_DDFX; 01497 01498 if (flags & WINEDDBLT_WAIT) 01499 flags &= ~WINEDDBLT_WAIT; 01500 01501 if (flags & WINEDDBLT_ASYNC) 01502 { 01503 static unsigned int once; 01504 01505 if (!once++) 01506 FIXME("Can't handle WINEDDBLT_ASYNC flag.\n"); 01507 flags &= ~WINEDDBLT_ASYNC; 01508 } 01509 01510 /* WINEDDBLT_DONOTWAIT appeared in DX7. */ 01511 if (flags & WINEDDBLT_DONOTWAIT) 01512 { 01513 static unsigned int once; 01514 01515 if (!once++) 01516 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag.\n"); 01517 flags &= ~WINEDDBLT_DONOTWAIT; 01518 } 01519 01520 if (!device->d3d_initialized) 01521 { 01522 WARN("D3D not initialized, using fallback.\n"); 01523 goto cpu; 01524 } 01525 01526 /* We want to avoid invalidating the sysmem location for converted 01527 * surfaces, since otherwise we'd have to convert the data back when 01528 * locking them. */ 01529 if (dst_surface->flags & SFLAG_CONVERTED) 01530 { 01531 WARN("Converted surface, using CPU blit.\n"); 01532 return surface_cpu_blt(dst_surface, &dst_rect, src_surface, &src_rect, flags, fx, filter); 01533 } 01534 01535 if (flags & ~simple_blit) 01536 { 01537 WARN("Using fallback for complex blit (%#x).\n", flags); 01538 goto fallback; 01539 } 01540 01541 if (src_surface && src_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN) 01542 src_swapchain = src_surface->container.u.swapchain; 01543 else 01544 src_swapchain = NULL; 01545 01546 if (dst_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN) 01547 dst_swapchain = dst_surface->container.u.swapchain; 01548 else 01549 dst_swapchain = NULL; 01550 01551 /* This isn't strictly needed. FBO blits for example could deal with 01552 * cross-swapchain blits by first downloading the source to a texture 01553 * before switching to the destination context. We just have this here to 01554 * not have to deal with the issue, since cross-swapchain blits should be 01555 * rare. */ 01556 if (src_swapchain && dst_swapchain && src_swapchain != dst_swapchain) 01557 { 01558 FIXME("Using fallback for cross-swapchain blit.\n"); 01559 goto fallback; 01560 } 01561 01562 scale = src_surface 01563 && (src_rect.right - src_rect.left != dst_rect.right - dst_rect.left 01564 || src_rect.bottom - src_rect.top != dst_rect.bottom - dst_rect.top); 01565 convert = src_surface && src_surface->resource.format->id != dst_surface->resource.format->id; 01566 01567 dst_ds_flags = dst_surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL); 01568 if (src_surface) 01569 src_ds_flags = src_surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL); 01570 else 01571 src_ds_flags = 0; 01572 01573 if (src_ds_flags || dst_ds_flags) 01574 { 01575 if (flags & WINEDDBLT_DEPTHFILL) 01576 { 01577 float depth; 01578 01579 TRACE("Depth fill.\n"); 01580 01581 if (!surface_convert_depth_to_float(dst_surface, fx->u5.dwFillDepth, &depth)) 01582 return WINED3DERR_INVALIDCALL; 01583 01584 if (SUCCEEDED(wined3d_surface_depth_fill(dst_surface, &dst_rect, depth))) 01585 return WINED3D_OK; 01586 } 01587 else 01588 { 01589 /* Accessing depth / stencil surfaces is supposed to fail while in 01590 * a scene, except for fills, which seem to work. */ 01591 if (device->inScene) 01592 { 01593 WARN("Rejecting depth / stencil access while in scene.\n"); 01594 return WINED3DERR_INVALIDCALL; 01595 } 01596 01597 if (src_ds_flags != dst_ds_flags) 01598 { 01599 WARN("Rejecting depth / stencil blit between incompatible formats.\n"); 01600 return WINED3DERR_INVALIDCALL; 01601 } 01602 01603 if (src_rect.top || src_rect.left 01604 || src_rect.bottom != src_surface->resource.height 01605 || src_rect.right != src_surface->resource.width) 01606 { 01607 WARN("Rejecting depth / stencil blit with invalid source rect %s.\n", 01608 wine_dbgstr_rect(&src_rect)); 01609 return WINED3DERR_INVALIDCALL; 01610 } 01611 01612 if (dst_rect.top || dst_rect.left 01613 || dst_rect.bottom != dst_surface->resource.height 01614 || dst_rect.right != dst_surface->resource.width) 01615 { 01616 WARN("Rejecting depth / stencil blit with invalid destination rect %s.\n", 01617 wine_dbgstr_rect(&src_rect)); 01618 return WINED3DERR_INVALIDCALL; 01619 } 01620 01621 if (scale) 01622 { 01623 WARN("Rejecting depth / stencil blit with mismatched surface sizes.\n"); 01624 return WINED3DERR_INVALIDCALL; 01625 } 01626 01627 if (SUCCEEDED(wined3d_surface_depth_blt(src_surface, &src_rect, dst_surface, &dst_rect))) 01628 return WINED3D_OK; 01629 } 01630 } 01631 else 01632 { 01633 /* In principle this would apply to depth blits as well, but we don't 01634 * implement those in the CPU blitter at the moment. */ 01635 if ((dst_surface->flags & SFLAG_INSYSMEM) 01636 && (!src_surface || (src_surface->flags & SFLAG_INSYSMEM))) 01637 { 01638 if (scale) 01639 TRACE("Not doing sysmem blit because of scaling.\n"); 01640 else if (convert) 01641 TRACE("Not doing sysmem blit because of format conversion.\n"); 01642 else 01643 return surface_cpu_blt(dst_surface, &dst_rect, src_surface, &src_rect, flags, fx, filter); 01644 } 01645 01646 if (flags & WINEDDBLT_COLORFILL) 01647 { 01648 struct wined3d_color color; 01649 01650 TRACE("Color fill.\n"); 01651 01652 if (!surface_convert_color_to_float(dst_surface, fx->u5.dwFillColor, &color)) 01653 goto fallback; 01654 01655 if (SUCCEEDED(surface_color_fill(dst_surface, &dst_rect, &color))) 01656 return WINED3D_OK; 01657 } 01658 else 01659 { 01660 TRACE("Color blit.\n"); 01661 01662 /* Upload */ 01663 if ((src_surface->flags & SFLAG_INSYSMEM) && !(dst_surface->flags & SFLAG_INSYSMEM)) 01664 { 01665 if (scale) 01666 TRACE("Not doing upload because of scaling.\n"); 01667 else if (convert) 01668 TRACE("Not doing upload because of format conversion.\n"); 01669 else 01670 { 01671 POINT dst_point = {dst_rect.left, dst_rect.top}; 01672 01673 if (SUCCEEDED(surface_upload_from_surface(dst_surface, &dst_point, src_surface, &src_rect))) 01674 { 01675 if (!surface_is_offscreen(dst_surface)) 01676 surface_load_location(dst_surface, dst_surface->draw_binding, NULL); 01677 return WINED3D_OK; 01678 } 01679 } 01680 } 01681 01682 /* Use present for back -> front blits. The idea behind this is 01683 * that present is potentially faster than a blit, in particular 01684 * when FBO blits aren't available. Some ddraw applications like 01685 * Half-Life and Prince of Persia 3D use Blt() from the backbuffer 01686 * to the frontbuffer instead of doing a Flip(). D3D8 and D3D9 01687 * applications can't blit directly to the frontbuffer. */ 01688 if (dst_swapchain && dst_swapchain->back_buffers 01689 && dst_surface == dst_swapchain->front_buffer 01690 && src_surface == dst_swapchain->back_buffers[0]) 01691 { 01692 enum wined3d_swap_effect swap_effect = dst_swapchain->desc.swap_effect; 01693 01694 TRACE("Using present for backbuffer -> frontbuffer blit.\n"); 01695 01696 /* Set the swap effect to COPY, we don't want the backbuffer 01697 * to become undefined. */ 01698 dst_swapchain->desc.swap_effect = WINED3D_SWAP_EFFECT_COPY; 01699 wined3d_swapchain_present(dst_swapchain, NULL, NULL, dst_swapchain->win_handle, NULL, 0); 01700 dst_swapchain->desc.swap_effect = swap_effect; 01701 01702 return WINED3D_OK; 01703 } 01704 01705 if (fbo_blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_BLIT, 01706 &src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format, 01707 &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format)) 01708 { 01709 TRACE("Using FBO blit.\n"); 01710 01711 surface_blt_fbo(device, filter, 01712 src_surface, src_surface->draw_binding, &src_rect, 01713 dst_surface, dst_surface->draw_binding, &dst_rect); 01714 surface_modify_location(dst_surface, dst_surface->draw_binding, TRUE); 01715 return WINED3D_OK; 01716 } 01717 01718 if (arbfp_blit.blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_BLIT, 01719 &src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format, 01720 &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format)) 01721 { 01722 TRACE("Using arbfp blit.\n"); 01723 01724 if (SUCCEEDED(arbfp_blit_surface(device, filter, src_surface, &src_rect, dst_surface, &dst_rect))) 01725 return WINED3D_OK; 01726 } 01727 } 01728 } 01729 01730 fallback: 01731 01732 /* Special cases for render targets. */ 01733 if ((dst_surface->resource.usage & WINED3DUSAGE_RENDERTARGET) 01734 || (src_surface && (src_surface->resource.usage & WINED3DUSAGE_RENDERTARGET))) 01735 { 01736 if (SUCCEEDED(IWineD3DSurfaceImpl_BltOverride(dst_surface, &dst_rect, 01737 src_surface, &src_rect, flags, fx, filter))) 01738 return WINED3D_OK; 01739 } 01740 01741 cpu: 01742 01743 /* For the rest call the X11 surface implementation. For render targets 01744 * this should be implemented OpenGL accelerated in BltOverride, other 01745 * blits are rather rare. */ 01746 return surface_cpu_blt(dst_surface, &dst_rect, src_surface, &src_rect, flags, fx, filter); 01747 } 01748 01749 HRESULT CDECL wined3d_surface_get_render_target_data(struct wined3d_surface *surface, 01750 struct wined3d_surface *render_target) 01751 { 01752 TRACE("surface %p, render_target %p.\n", surface, render_target); 01753 01754 /* TODO: Check surface sizes, pools, etc. */ 01755 01756 if (render_target->resource.multisample_type) 01757 return WINED3DERR_INVALIDCALL; 01758 01759 return wined3d_surface_blt(surface, NULL, render_target, NULL, 0, NULL, WINED3D_TEXF_POINT); 01760 } 01761 01762 /* Context activation is done by the caller. */ 01763 static void surface_remove_pbo(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info) 01764 { 01765 if (surface->flags & SFLAG_DIBSECTION) 01766 { 01767 surface->resource.allocatedMemory = surface->dib.bitmap_data; 01768 } 01769 else 01770 { 01771 if (!surface->resource.heapMemory) 01772 surface->resource.heapMemory = HeapAlloc(GetProcessHeap(), 0, surface->resource.size + RESOURCE_ALIGNMENT); 01773 else if (!(surface->flags & SFLAG_CLIENT)) 01774 ERR("Surface %p has heapMemory %p and flags %#x.\n", 01775 surface, surface->resource.heapMemory, surface->flags); 01776 01777 surface->resource.allocatedMemory = (BYTE *)(((ULONG_PTR)surface->resource.heapMemory 01778 + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1)); 01779 } 01780 01781 ENTER_GL(); 01782 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo)); 01783 checkGLcall("glBindBufferARB(GL_PIXEL_UNPACK_BUFFER, surface->pbo)"); 01784 GL_EXTCALL(glGetBufferSubDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0, 01785 surface->resource.size, surface->resource.allocatedMemory)); 01786 checkGLcall("glGetBufferSubDataARB"); 01787 GL_EXTCALL(glDeleteBuffersARB(1, &surface->pbo)); 01788 checkGLcall("glDeleteBuffersARB"); 01789 LEAVE_GL(); 01790 01791 surface->pbo = 0; 01792 surface->flags &= ~SFLAG_PBO; 01793 } 01794 01795 /* Do not call while under the GL lock. */ 01796 static void surface_unload(struct wined3d_resource *resource) 01797 { 01798 struct wined3d_surface *surface = surface_from_resource(resource); 01799 struct wined3d_renderbuffer_entry *entry, *entry2; 01800 struct wined3d_device *device = resource->device; 01801 const struct wined3d_gl_info *gl_info; 01802 struct wined3d_context *context; 01803 01804 TRACE("surface %p.\n", surface); 01805 01806 if (resource->pool == WINED3D_POOL_DEFAULT) 01807 { 01808 /* Default pool resources are supposed to be destroyed before Reset is called. 01809 * Implicit resources stay however. So this means we have an implicit render target 01810 * or depth stencil. The content may be destroyed, but we still have to tear down 01811 * opengl resources, so we cannot leave early. 01812 * 01813 * Put the surfaces into sysmem, and reset the content. The D3D content is undefined, 01814 * but we can't set the sysmem INDRAWABLE because when we're rendering the swapchain 01815 * or the depth stencil into an FBO the texture or render buffer will be removed 01816 * and all flags get lost 01817 */ 01818 if (!(surface->flags & SFLAG_PBO)) 01819 surface_init_sysmem(surface); 01820 /* We also get here when the ddraw swapchain is destroyed, for example 01821 * for a mode switch. In this case this surface won't necessarily be 01822 * an implicit surface. We have to mark it lost so that the 01823 * application can restore it after the mode switch. */ 01824 surface->flags |= SFLAG_LOST; 01825 } 01826 else 01827 { 01828 /* Load the surface into system memory */ 01829 surface_load_location(surface, SFLAG_INSYSMEM, NULL); 01830 surface_modify_location(surface, surface->draw_binding, FALSE); 01831 } 01832 surface_modify_location(surface, SFLAG_INTEXTURE, FALSE); 01833 surface_modify_location(surface, SFLAG_INSRGBTEX, FALSE); 01834 surface->flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED); 01835 01836 context = context_acquire(device, NULL); 01837 gl_info = context->gl_info; 01838 01839 /* Destroy PBOs, but load them into real sysmem before */ 01840 if (surface->flags & SFLAG_PBO) 01841 surface_remove_pbo(surface, gl_info); 01842 01843 /* Destroy fbo render buffers. This is needed for implicit render targets, for 01844 * all application-created targets the application has to release the surface 01845 * before calling _Reset 01846 */ 01847 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &surface->renderbuffers, struct wined3d_renderbuffer_entry, entry) 01848 { 01849 ENTER_GL(); 01850 gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id); 01851 LEAVE_GL(); 01852 list_remove(&entry->entry); 01853 HeapFree(GetProcessHeap(), 0, entry); 01854 } 01855 list_init(&surface->renderbuffers); 01856 surface->current_renderbuffer = NULL; 01857 01858 ENTER_GL(); 01859 01860 /* If we're in a texture, the texture name belongs to the texture. 01861 * Otherwise, destroy it. */ 01862 if (surface->container.type != WINED3D_CONTAINER_TEXTURE) 01863 { 01864 glDeleteTextures(1, &surface->texture_name); 01865 surface->texture_name = 0; 01866 glDeleteTextures(1, &surface->texture_name_srgb); 01867 surface->texture_name_srgb = 0; 01868 } 01869 if (surface->rb_multisample) 01870 { 01871 gl_info->fbo_ops.glDeleteRenderbuffers(1, &surface->rb_multisample); 01872 surface->rb_multisample = 0; 01873 } 01874 if (surface->rb_resolved) 01875 { 01876 gl_info->fbo_ops.glDeleteRenderbuffers(1, &surface->rb_resolved); 01877 surface->rb_resolved = 0; 01878 } 01879 01880 LEAVE_GL(); 01881 01882 context_release(context); 01883 01884 resource_unload(resource); 01885 } 01886 01887 static const struct wined3d_resource_ops surface_resource_ops = 01888 { 01889 surface_unload, 01890 }; 01891 01892 static const struct wined3d_surface_ops surface_ops = 01893 { 01894 surface_private_setup, 01895 surface_realize_palette, 01896 surface_map, 01897 surface_unmap, 01898 }; 01899 01900 /***************************************************************************** 01901 * Initializes the GDI surface, aka creates the DIB section we render to 01902 * The DIB section creation is done by calling GetDC, which will create the 01903 * section and releasing the dc to allow the app to use it. The dib section 01904 * will stay until the surface is released 01905 * 01906 * GDI surfaces do not need to be a power of 2 in size, so the pow2 sizes 01907 * are set to the real sizes to save memory. The NONPOW2 flag is unset to 01908 * avoid confusion in the shared surface code. 01909 * 01910 * Returns: 01911 * WINED3D_OK on success 01912 * The return values of called methods on failure 01913 * 01914 *****************************************************************************/ 01915 static HRESULT gdi_surface_private_setup(struct wined3d_surface *surface) 01916 { 01917 HRESULT hr; 01918 01919 TRACE("surface %p.\n", surface); 01920 01921 if (surface->resource.usage & WINED3DUSAGE_OVERLAY) 01922 { 01923 ERR("Overlays not yet supported by GDI surfaces.\n"); 01924 return WINED3DERR_INVALIDCALL; 01925 } 01926 01927 /* Sysmem textures have memory already allocated - release it, 01928 * this avoids an unnecessary memcpy. */ 01929 hr = surface_create_dib_section(surface); 01930 if (SUCCEEDED(hr)) 01931 { 01932 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory); 01933 surface->resource.heapMemory = NULL; 01934 surface->resource.allocatedMemory = surface->dib.bitmap_data; 01935 } 01936 01937 /* We don't mind the nonpow2 stuff in GDI. */ 01938 surface->pow2Width = surface->resource.width; 01939 surface->pow2Height = surface->resource.height; 01940 01941 return WINED3D_OK; 01942 } 01943 01944 static void gdi_surface_realize_palette(struct wined3d_surface *surface) 01945 { 01946 struct wined3d_palette *palette = surface->palette; 01947 01948 TRACE("surface %p.\n", surface); 01949 01950 if (!palette) return; 01951 01952 if (surface->flags & SFLAG_DIBSECTION) 01953 { 01954 RGBQUAD col[256]; 01955 unsigned int i; 01956 01957 TRACE("Updating the DC's palette.\n"); 01958 01959 for (i = 0; i < 256; ++i) 01960 { 01961 col[i].rgbRed = palette->palents[i].peRed; 01962 col[i].rgbGreen = palette->palents[i].peGreen; 01963 col[i].rgbBlue = palette->palents[i].peBlue; 01964 col[i].rgbReserved = 0; 01965 } 01966 SetDIBColorTable(surface->hDC, 0, 256, col); 01967 } 01968 01969 /* Update the image because of the palette change. Some games like e.g. 01970 * Red Alert call SetEntries a lot to implement fading. */ 01971 /* Tell the swapchain to update the screen. */ 01972 if (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN) 01973 { 01974 struct wined3d_swapchain *swapchain = surface->container.u.swapchain; 01975 if (surface == swapchain->front_buffer) 01976 { 01977 x11_copy_to_screen(swapchain, NULL); 01978 } 01979 } 01980 } 01981 01982 static void gdi_surface_map(struct wined3d_surface *surface, const RECT *rect, DWORD flags) 01983 { 01984 TRACE("surface %p, rect %s, flags %#x.\n", 01985 surface, wine_dbgstr_rect(rect), flags); 01986 01987 if (!(surface->flags & SFLAG_DIBSECTION)) 01988 { 01989 /* This happens on gdi surfaces if the application set a user pointer 01990 * and resets it. Recreate the DIB section. */ 01991 surface_create_dib_section(surface); 01992 surface->resource.allocatedMemory = surface->dib.bitmap_data; 01993 } 01994 } 01995 01996 static void gdi_surface_unmap(struct wined3d_surface *surface) 01997 { 01998 TRACE("surface %p.\n", surface); 01999 02000 /* Tell the swapchain to update the screen. */ 02001 if (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN) 02002 { 02003 struct wined3d_swapchain *swapchain = surface->container.u.swapchain; 02004 if (surface == swapchain->front_buffer) 02005 { 02006 x11_copy_to_screen(swapchain, &surface->lockedRect); 02007 } 02008 } 02009 02010 memset(&surface->lockedRect, 0, sizeof(RECT)); 02011 } 02012 02013 static const struct wined3d_surface_ops gdi_surface_ops = 02014 { 02015 gdi_surface_private_setup, 02016 gdi_surface_realize_palette, 02017 gdi_surface_map, 02018 gdi_surface_unmap, 02019 }; 02020 02021 void surface_set_texture_name(struct wined3d_surface *surface, GLuint new_name, BOOL srgb) 02022 { 02023 GLuint *name; 02024 DWORD flag; 02025 02026 TRACE("surface %p, new_name %u, srgb %#x.\n", surface, new_name, srgb); 02027 02028 if(srgb) 02029 { 02030 name = &surface->texture_name_srgb; 02031 flag = SFLAG_INSRGBTEX; 02032 } 02033 else 02034 { 02035 name = &surface->texture_name; 02036 flag = SFLAG_INTEXTURE; 02037 } 02038 02039 if (!*name && new_name) 02040 { 02041 /* FIXME: We shouldn't need to remove SFLAG_INTEXTURE if the 02042 * surface has no texture name yet. See if we can get rid of this. */ 02043 if (surface->flags & flag) 02044 { 02045 ERR("Surface has %s set, but no texture name.\n", debug_surflocation(flag)); 02046 surface_modify_location(surface, flag, FALSE); 02047 } 02048 } 02049 02050 *name = new_name; 02051 surface_force_reload(surface); 02052 } 02053 02054 void surface_set_texture_target(struct wined3d_surface *surface, GLenum target) 02055 { 02056 TRACE("surface %p, target %#x.\n", surface, target); 02057 02058 if (surface->texture_target != target) 02059 { 02060 if (target == GL_TEXTURE_RECTANGLE_ARB) 02061 { 02062 surface->flags &= ~SFLAG_NORMCOORD; 02063 } 02064 else if (surface->texture_target == GL_TEXTURE_RECTANGLE_ARB) 02065 { 02066 surface->flags |= SFLAG_NORMCOORD; 02067 } 02068 } 02069 surface->texture_target = target; 02070 surface_force_reload(surface); 02071 } 02072 02073 /* Context activation is done by the caller. */ 02074 void surface_bind(struct wined3d_surface *surface, struct wined3d_context *context, BOOL srgb) 02075 { 02076 TRACE("surface %p, context %p, srgb %#x.\n", surface, context, srgb); 02077 02078 if (surface->container.type == WINED3D_CONTAINER_TEXTURE) 02079 { 02080 struct wined3d_texture *texture = surface->container.u.texture; 02081 02082 TRACE("Passing to container (%p).\n", texture); 02083 texture->texture_ops->texture_bind(texture, context, srgb); 02084 } 02085 else 02086 { 02087 if (surface->texture_level) 02088 { 02089 ERR("Standalone surface %p is non-zero texture level %u.\n", 02090 surface, surface->texture_level); 02091 } 02092 02093 if (srgb) 02094 ERR("Trying to bind standalone surface %p as sRGB.\n", surface); 02095 02096 ENTER_GL(); 02097 02098 if (!surface->texture_name) 02099 { 02100 glGenTextures(1, &surface->texture_name); 02101 checkGLcall("glGenTextures"); 02102 02103 TRACE("Surface %p given name %u.\n", surface, surface->texture_name); 02104 02105 context_bind_texture(context, surface->texture_target, surface->texture_name); 02106 glTexParameteri(surface->texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 02107 glTexParameteri(surface->texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 02108 glTexParameteri(surface->texture_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); 02109 glTexParameteri(surface->texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 02110 glTexParameteri(surface->texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 02111 checkGLcall("glTexParameteri"); 02112 } 02113 else 02114 { 02115 context_bind_texture(context, surface->texture_target, surface->texture_name); 02116 } 02117 02118 LEAVE_GL(); 02119 } 02120 } 02121 02122 /* This call just downloads data, the caller is responsible for binding the 02123 * correct texture. */ 02124 /* Context activation is done by the caller. */ 02125 static void surface_download_data(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info) 02126 { 02127 const struct wined3d_format *format = surface->resource.format; 02128 02129 /* Only support read back of converted P8 surfaces. */ 02130 if (surface->flags & SFLAG_CONVERTED && format->id != WINED3DFMT_P8_UINT) 02131 { 02132 ERR("Trying to read back converted surface %p with format %s.\n", surface, debug_d3dformat(format->id)); 02133 return; 02134 } 02135 02136 ENTER_GL(); 02137 02138 if (format->flags & WINED3DFMT_FLAG_COMPRESSED) 02139 { 02140 TRACE("(%p) : Calling glGetCompressedTexImageARB level %d, format %#x, type %#x, data %p.\n", 02141 surface, surface->texture_level, format->glFormat, format->glType, 02142 surface->resource.allocatedMemory); 02143 02144 if (surface->flags & SFLAG_PBO) 02145 { 02146 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, surface->pbo)); 02147 checkGLcall("glBindBufferARB"); 02148 GL_EXTCALL(glGetCompressedTexImageARB(surface->texture_target, surface->texture_level, NULL)); 02149 checkGLcall("glGetCompressedTexImageARB"); 02150 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0)); 02151 checkGLcall("glBindBufferARB"); 02152 } 02153 else 02154 { 02155 GL_EXTCALL(glGetCompressedTexImageARB(surface->texture_target, 02156 surface->texture_level, surface->resource.allocatedMemory)); 02157 checkGLcall("glGetCompressedTexImageARB"); 02158 } 02159 02160 LEAVE_GL(); 02161 } 02162 else 02163 { 02164 void *mem; 02165 GLenum gl_format = format->glFormat; 02166 GLenum gl_type = format->glType; 02167 int src_pitch = 0; 02168 int dst_pitch = 0; 02169 02170 /* In case of P8 the index is stored in the alpha component if the primary render target uses P8. */ 02171 if (format->id == WINED3DFMT_P8_UINT && primary_render_target_is_p8(surface->resource.device)) 02172 { 02173 gl_format = GL_ALPHA; 02174 gl_type = GL_UNSIGNED_BYTE; 02175 } 02176 02177 if (surface->flags & SFLAG_NONPOW2) 02178 { 02179 unsigned char alignment = surface->resource.device->surface_alignment; 02180 src_pitch = format->byte_count * surface->pow2Width; 02181 dst_pitch = wined3d_surface_get_pitch(surface); 02182 src_pitch = (src_pitch + alignment - 1) & ~(alignment - 1); 02183 mem = HeapAlloc(GetProcessHeap(), 0, src_pitch * surface->pow2Height); 02184 } 02185 else 02186 { 02187 mem = surface->resource.allocatedMemory; 02188 } 02189 02190 TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n", 02191 surface, surface->texture_level, gl_format, gl_type, mem); 02192 02193 if (surface->flags & SFLAG_PBO) 02194 { 02195 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, surface->pbo)); 02196 checkGLcall("glBindBufferARB"); 02197 02198 glGetTexImage(surface->texture_target, surface->texture_level, gl_format, gl_type, NULL); 02199 checkGLcall("glGetTexImage"); 02200 02201 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0)); 02202 checkGLcall("glBindBufferARB"); 02203 } 02204 else 02205 { 02206 glGetTexImage(surface->texture_target, surface->texture_level, gl_format, gl_type, mem); 02207 checkGLcall("glGetTexImage"); 02208 } 02209 LEAVE_GL(); 02210 02211 if (surface->flags & SFLAG_NONPOW2) 02212 { 02213 const BYTE *src_data; 02214 BYTE *dst_data; 02215 UINT y; 02216 /* 02217 * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing 02218 * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to 02219 * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width. 02220 * 02221 * We're doing this... 02222 * 02223 * instead of boxing the texture : 02224 * |<-texture width ->| -->pow2width| /\ 02225 * |111111111111111111| | | 02226 * |222 Texture 222222| boxed empty | texture height 02227 * |3333 Data 33333333| | | 02228 * |444444444444444444| | \/ 02229 * ----------------------------------- | 02230 * | boxed empty | boxed empty | pow2height 02231 * | | | \/ 02232 * ----------------------------------- 02233 * 02234 * 02235 * we're repacking the data to the expected texture width 02236 * 02237 * |<-texture width ->| -->pow2width| /\ 02238 * |111111111111111111222222222222222| | 02239 * |222333333333333333333444444444444| texture height 02240 * |444444 | | 02241 * | | \/ 02242 * | | | 02243 * | empty | pow2height 02244 * | | \/ 02245 * ----------------------------------- 02246 * 02247 * == is the same as 02248 * 02249 * |<-texture width ->| /\ 02250 * |111111111111111111| 02251 * |222222222222222222|texture height 02252 * |333333333333333333| 02253 * |444444444444444444| \/ 02254 * -------------------- 02255 * 02256 * this also means that any references to allocatedMemory should work with the data as if were a 02257 * standard texture with a non-power2 width instead of texture boxed up to be a power2 texture. 02258 * 02259 * internally the texture is still stored in a boxed format so any references to textureName will 02260 * get a boxed texture with width pow2width and not a texture of width resource.width. 02261 * 02262 * Performance should not be an issue, because applications normally do not lock the surfaces when 02263 * rendering. If an app does, the SFLAG_DYNLOCK flag will kick in and the memory copy won't be released, 02264 * and doesn't have to be re-read. */ 02265 src_data = mem; 02266 dst_data = surface->resource.allocatedMemory; 02267 TRACE("(%p) : Repacking the surface data from pitch %d to pitch %d\n", surface, src_pitch, dst_pitch); 02268 for (y = 1; y < surface->resource.height; ++y) 02269 { 02270 /* skip the first row */ 02271 src_data += src_pitch; 02272 dst_data += dst_pitch; 02273 memcpy(dst_data, src_data, dst_pitch); 02274 } 02275 02276 HeapFree(GetProcessHeap(), 0, mem); 02277 } 02278 } 02279 02280 /* Surface has now been downloaded */ 02281 surface->flags |= SFLAG_INSYSMEM; 02282 } 02283 02284 /* This call just uploads data, the caller is responsible for binding the 02285 * correct texture. */ 02286 /* Context activation is done by the caller. */ 02287 static void surface_upload_data(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info, 02288 const struct wined3d_format *format, const RECT *src_rect, UINT src_pitch, const POINT *dst_point, 02289 BOOL srgb, const struct wined3d_bo_address *data) 02290 { 02291 UINT update_w = src_rect->right - src_rect->left; 02292 UINT update_h = src_rect->bottom - src_rect->top; 02293 02294 TRACE("surface %p, gl_info %p, format %s, src_rect %s, src_pitch %u, dst_point %s, srgb %#x, data {%#x:%p}.\n", 02295 surface, gl_info, debug_d3dformat(format->id), wine_dbgstr_rect(src_rect), src_pitch, 02296 wine_dbgstr_point(dst_point), srgb, data->buffer_object, data->addr); 02297 02298 if (surface->flags & SFLAG_LOCKED) 02299 { 02300 WARN("Uploading a surface that is currently mapped, setting SFLAG_PIN_SYSMEM.\n"); 02301 surface->flags |= SFLAG_PIN_SYSMEM; 02302 } 02303 02304 if (format->heightscale != 1.0f && format->heightscale != 0.0f) 02305 update_h *= format->heightscale; 02306 02307 ENTER_GL(); 02308 02309 if (data->buffer_object) 02310 { 02311 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, data->buffer_object)); 02312 checkGLcall("glBindBufferARB"); 02313 } 02314 02315 if (format->flags & WINED3DFMT_FLAG_COMPRESSED) 02316 { 02317 UINT row_length = wined3d_format_calculate_size(format, 1, update_w, 1); 02318 UINT row_count = (update_h + format->block_height - 1) / format->block_height; 02319 const BYTE *addr = data->addr; 02320 GLenum internal; 02321 02322 addr += (src_rect->top / format->block_height) * src_pitch; 02323 addr += (src_rect->left / format->block_width) * format->block_byte_count; 02324 02325 if (srgb) 02326 internal = format->glGammaInternal; 02327 else if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET && surface_is_offscreen(surface)) 02328 internal = format->rtInternal; 02329 else 02330 internal = format->glInternal; 02331 02332 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, " 02333 "format %#x, image_size %#x, addr %p.\n", surface->texture_target, surface->texture_level, 02334 dst_point->x, dst_point->y, update_w, update_h, internal, row_count * row_length, addr); 02335 02336 if (row_length == src_pitch) 02337 { 02338 GL_EXTCALL(glCompressedTexSubImage2DARB(surface->texture_target, surface->texture_level, 02339 dst_point->x, dst_point->y, update_w, update_h, internal, row_count * row_length, addr)); 02340 } 02341 else 02342 { 02343 UINT row, y; 02344 02345 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we 02346 * can't use the unpack row length like below. */ 02347 for (row = 0, y = dst_point->y; row < row_count; ++row) 02348 { 02349 GL_EXTCALL(glCompressedTexSubImage2DARB(surface->texture_target, surface->texture_level, 02350 dst_point->x, y, update_w, format->block_height, internal, row_length, addr)); 02351 y += format->block_height; 02352 addr += src_pitch; 02353 } 02354 } 02355 checkGLcall("glCompressedTexSubImage2DARB"); 02356 } 02357 else 02358 { 02359 const BYTE *addr = data->addr; 02360 02361 addr += src_rect->top * src_pitch; 02362 addr += src_rect->left * format->byte_count; 02363 02364 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, addr %p.\n", 02365 surface->texture_target, surface->texture_level, dst_point->x, dst_point->y, 02366 update_w, update_h, format->glFormat, format->glType, addr); 02367 02368 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_pitch / format->byte_count); 02369 glTexSubImage2D(surface->texture_target, surface->texture_level, dst_point->x, dst_point->y, 02370 update_w, update_h, format->glFormat, format->glType, addr); 02371 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); 02372 checkGLcall("glTexSubImage2D"); 02373 } 02374 02375 if (data->buffer_object) 02376 { 02377 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0)); 02378 checkGLcall("glBindBufferARB"); 02379 } 02380 02381 LEAVE_GL(); 02382 02383 if (wined3d_settings.strict_draw_ordering) 02384 wglFlush(); 02385 02386 if (gl_info->quirks & WINED3D_QUIRK_FBO_TEX_UPDATE) 02387 { 02388 struct wined3d_device *device = surface->resource.device; 02389 unsigned int i; 02390 02391 for (i = 0; i < device->context_count; ++i) 02392 { 02393 context_surface_update(device->contexts[i], surface); 02394 } 02395 } 02396 } 02397 02398 HRESULT surface_upload_from_surface(struct wined3d_surface *dst_surface, const POINT *dst_point, 02399 struct wined3d_surface *src_surface, const RECT *src_rect) 02400 { 02401 const struct wined3d_format *src_format; 02402 const struct wined3d_format *dst_format; 02403 const struct wined3d_gl_info *gl_info; 02404 struct wined3d_context *context; 02405 struct wined3d_bo_address data; 02406 struct wined3d_format format; 02407 UINT update_w, update_h; 02408 CONVERT_TYPES convert; 02409 UINT dst_w, dst_h; 02410 UINT src_w, src_h; 02411 UINT src_pitch; 02412 POINT p; 02413 RECT r; 02414 02415 TRACE("dst_surface %p, dst_point %s, src_surface %p, src_rect %s.\n", 02416 dst_surface, wine_dbgstr_point(dst_point), 02417 src_surface, wine_dbgstr_rect(src_rect)); 02418 02419 src_format = src_surface->resource.format; 02420 dst_format = dst_surface->resource.format; 02421 02422 if (src_format->id != dst_format->id) 02423 { 02424 WARN("Source and destination surfaces should have the same format.\n"); 02425 return WINED3DERR_INVALIDCALL; 02426 } 02427 02428 if (!dst_point) 02429 { 02430 p.x = 0; 02431 p.y = 0; 02432 dst_point = &p; 02433 } 02434 else if (dst_point->x < 0 || dst_point->y < 0) 02435 { 02436 WARN("Invalid destination point.\n"); 02437 return WINED3DERR_INVALIDCALL; 02438 } 02439 02440 if (!src_rect) 02441 { 02442 r.left = 0; 02443 r.top = 0; 02444 r.right = src_surface->resource.width; 02445 r.bottom = src_surface->resource.height; 02446 src_rect = &r; 02447 } 02448 else if (src_rect->left < 0 || src_rect->left >= src_rect->right 02449 || src_rect->top < 0 || src_rect->top >= src_rect->bottom) 02450 { 02451 WARN("Invalid source rectangle.\n"); 02452 return WINED3DERR_INVALIDCALL; 02453 } 02454 02455 src_w = src_surface->resource.width; 02456 src_h = src_surface->resource.height; 02457 02458 dst_w = dst_surface->resource.width; 02459 dst_h = dst_surface->resource.height; 02460 02461 update_w = src_rect->right - src_rect->left; 02462 update_h = src_rect->bottom - src_rect->top; 02463 02464 if (update_w > dst_w || dst_point->x > dst_w - update_w 02465 || update_h > dst_h || dst_point->y > dst_h - update_h) 02466 { 02467 WARN("Destination out of bounds.\n"); 02468 return WINED3DERR_INVALIDCALL; 02469 } 02470 02471 /* NPOT block sizes would be silly. */ 02472 if ((src_format->flags & WINED3DFMT_FLAG_BLOCKS) 02473 && ((update_w & (src_format->block_width - 1) || update_h & (src_format->block_height - 1)) 02474 && (src_w != update_w || dst_w != update_w || src_h != update_h || dst_h != update_h))) 02475 { 02476 WARN("Update rect not block-aligned.\n"); 02477 return WINED3DERR_INVALIDCALL; 02478 } 02479 02480 /* Use wined3d_surface_blt() instead of uploading directly if we need conversion. */ 02481 d3dfmt_get_conv(dst_surface, FALSE, TRUE, &format, &convert); 02482 if (convert != NO_CONVERSION || format.convert) 02483 { 02484 RECT dst_rect = {dst_point->x, dst_point->y, dst_point->x + update_w, dst_point->y + update_h}; 02485 return wined3d_surface_blt(dst_surface, &dst_rect, src_surface, src_rect, 0, NULL, WINED3D_TEXF_POINT); 02486 } 02487 02488 context = context_acquire(dst_surface->resource.device, NULL); 02489 gl_info = context->gl_info; 02490 02491 /* Only load the surface for partial updates. For newly allocated texture 02492 * the texture wouldn't be the current location, and we'd upload zeroes 02493 * just to overwrite them again. */ 02494 if (update_w == dst_w && update_h == dst_h) 02495 surface_prepare_texture(dst_surface, context, FALSE); 02496 else 02497 surface_load_location(dst_surface, SFLAG_INTEXTURE, NULL); 02498 surface_bind(dst_surface, context, FALSE); 02499 02500 data.buffer_object = src_surface->pbo; 02501 data.addr = src_surface->resource.allocatedMemory; 02502 src_pitch = wined3d_surface_get_pitch(src_surface); 02503 02504 surface_upload_data(dst_surface, gl_info, src_format, src_rect, src_pitch, dst_point, FALSE, &data); 02505 02506 invalidate_active_texture(dst_surface->resource.device, context); 02507 02508 context_release(context); 02509 02510 surface_modify_location(dst_surface, SFLAG_INTEXTURE, TRUE); 02511 return WINED3D_OK; 02512 } 02513 02514 /* This call just allocates the texture, the caller is responsible for binding 02515 * the correct texture. */ 02516 /* Context activation is done by the caller. */ 02517 static void surface_allocate_surface(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info, 02518 const struct wined3d_format *format, BOOL srgb) 02519 { 02520 BOOL enable_client_storage = FALSE; 02521 GLsizei width = surface->pow2Width; 02522 GLsizei height = surface->pow2Height; 02523 const BYTE *mem = NULL; 02524 GLenum internal; 02525 02526 if (srgb) 02527 { 02528 internal = format->glGammaInternal; 02529 } 02530 else if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET && surface_is_offscreen(surface)) 02531 { 02532 internal = format->rtInternal; 02533 } 02534 else 02535 { 02536 internal = format->glInternal; 02537 } 02538 02539 if (format->heightscale != 1.0f && format->heightscale != 0.0f) height *= format->heightscale; 02540 02541 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", 02542 surface, surface->texture_target, surface->texture_level, debug_d3dformat(format->id), 02543 internal, width, height, format->glFormat, format->glType); 02544 02545 ENTER_GL(); 02546 02547 if (gl_info->supported[APPLE_CLIENT_STORAGE]) 02548 { 02549 if (surface->flags & (SFLAG_NONPOW2 | SFLAG_DIBSECTION | SFLAG_CONVERTED) 02550 || !surface->resource.allocatedMemory) 02551 { 02552 /* In some cases we want to disable client storage. 02553 * SFLAG_NONPOW2 has a bigger opengl texture than the client memory, and different pitches 02554 * SFLAG_DIBSECTION: Dibsections may have read / write protections on the memory. Avoid issues... 02555 * SFLAG_CONVERTED: The conversion destination memory is freed after loading the surface 02556 * allocatedMemory == NULL: Not defined in the extension. Seems to disable client storage effectively 02557 */ 02558 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE); 02559 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)"); 02560 surface->flags &= ~SFLAG_CLIENT; 02561 enable_client_storage = TRUE; 02562 } 02563 else 02564 { 02565 surface->flags |= SFLAG_CLIENT; 02566 02567 /* Point OpenGL to our allocated texture memory. Do not use 02568 * resource.allocatedMemory here because it might point into a 02569 * PBO. Instead use heapMemory, but get the alignment right. */ 02570 mem = (BYTE *)(((ULONG_PTR)surface->resource.heapMemory 02571 + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1)); 02572 } 02573 } 02574 02575 if (format->flags & WINED3DFMT_FLAG_COMPRESSED && mem) 02576 { 02577 GL_EXTCALL(glCompressedTexImage2DARB(surface->texture_target, surface->texture_level, 02578 internal, width, height, 0, surface->resource.size, mem)); 02579 checkGLcall("glCompressedTexImage2DARB"); 02580 } 02581 else 02582 { 02583 glTexImage2D(surface->texture_target, surface->texture_level, 02584 internal, width, height, 0, format->glFormat, format->glType, mem); 02585 checkGLcall("glTexImage2D"); 02586 } 02587 02588 if(enable_client_storage) { 02589 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE); 02590 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)"); 02591 } 02592 LEAVE_GL(); 02593 } 02594 02595 /* In D3D the depth stencil dimensions have to be greater than or equal to the 02596 * render target dimensions. With FBOs, the dimensions have to be an exact match. */ 02597 /* TODO: We should synchronize the renderbuffer's content with the texture's content. */ 02598 /* GL locking is done by the caller */ 02599 void surface_set_compatible_renderbuffer(struct wined3d_surface *surface, const struct wined3d_surface *rt) 02600 { 02601 const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info; 02602 struct wined3d_renderbuffer_entry *entry; 02603 GLuint renderbuffer = 0; 02604 unsigned int src_width, src_height; 02605 unsigned int width, height; 02606 02607 if (rt && rt->resource.format->id != WINED3DFMT_NULL) 02608 { 02609 width = rt->pow2Width; 02610 height = rt->pow2Height; 02611 } 02612 else 02613 { 02614 width = surface->pow2Width; 02615 height = surface->pow2Height; 02616 } 02617 02618 src_width = surface->pow2Width; 02619 src_height = surface->pow2Height; 02620 02621 /* A depth stencil smaller than the render target is not valid */ 02622 if (width > src_width || height > src_height) return; 02623 02624 /* Remove any renderbuffer set if the sizes match */ 02625 if (gl_info->supported[ARB_FRAMEBUFFER_OBJECT] 02626 || (width == src_width && height == src_height)) 02627 { 02628 surface->current_renderbuffer = NULL; 02629 return; 02630 } 02631 02632 /* Look if we've already got a renderbuffer of the correct dimensions */ 02633 LIST_FOR_EACH_ENTRY(entry, &surface->renderbuffers, struct wined3d_renderbuffer_entry, entry) 02634 { 02635 if (entry->width == width && entry->height == height) 02636 { 02637 renderbuffer = entry->id; 02638 surface->current_renderbuffer = entry; 02639 break; 02640 } 02641 } 02642 02643 if (!renderbuffer) 02644 { 02645 gl_info->fbo_ops.glGenRenderbuffers(1, &renderbuffer); 02646 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer); 02647 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER, 02648 surface->resource.format->glInternal, width, height); 02649 02650 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry)); 02651 entry->width = width; 02652 entry->height = height; 02653 entry->id = renderbuffer; 02654 list_add_head(&surface->renderbuffers, &entry->entry); 02655 02656 surface->current_renderbuffer = entry; 02657 } 02658 02659 checkGLcall("set_compatible_renderbuffer"); 02660 } 02661 02662 GLenum surface_get_gl_buffer(const struct wined3d_surface *surface) 02663 { 02664 const struct wined3d_swapchain *swapchain = surface->container.u.swapchain; 02665 02666 TRACE("surface %p.\n", surface); 02667 02668 if (surface->container.type != WINED3D_CONTAINER_SWAPCHAIN) 02669 { 02670 ERR("Surface %p is not on a swapchain.\n", surface); 02671 return GL_NONE; 02672 } 02673 02674 if (swapchain->back_buffers && swapchain->back_buffers[0] == surface) 02675 { 02676 if (swapchain->render_to_fbo) 02677 { 02678 TRACE("Returning GL_COLOR_ATTACHMENT0\n"); 02679 return GL_COLOR_ATTACHMENT0; 02680 } 02681 TRACE("Returning GL_BACK\n"); 02682 return GL_BACK; 02683 } 02684 else if (surface == swapchain->front_buffer) 02685 { 02686 TRACE("Returning GL_FRONT\n"); 02687 return GL_FRONT; 02688 } 02689 02690 FIXME("Higher back buffer, returning GL_BACK\n"); 02691 return GL_BACK; 02692 } 02693 02694 /* Slightly inefficient way to handle multiple dirty rects but it works :) */ 02695 void surface_add_dirty_rect(struct wined3d_surface *surface, const struct wined3d_box *dirty_rect) 02696 { 02697 TRACE("surface %p, dirty_rect %p.\n", surface, dirty_rect); 02698 02699 if (!(surface->flags & SFLAG_INSYSMEM) && (surface->flags & SFLAG_INTEXTURE)) 02700 /* No partial locking for textures yet. */ 02701 surface_load_location(surface, SFLAG_INSYSMEM, NULL); 02702 02703 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE); 02704 if (dirty_rect) 02705 { 02706 surface->dirtyRect.left = min(surface->dirtyRect.left, dirty_rect->left); 02707 surface->dirtyRect.top = min(surface->dirtyRect.top, dirty_rect->top); 02708 surface->dirtyRect.right = max(surface->dirtyRect.right, dirty_rect->right); 02709 surface->dirtyRect.bottom = max(surface->dirtyRect.bottom, dirty_rect->bottom); 02710 } 02711 else 02712 { 02713 surface->dirtyRect.left = 0; 02714 surface->dirtyRect.top = 0; 02715 surface->dirtyRect.right = surface->resource.width; 02716 surface->dirtyRect.bottom = surface->resource.height; 02717 } 02718 02719 /* if the container is a texture then mark it dirty. */ 02720 if (surface->container.type == WINED3D_CONTAINER_TEXTURE) 02721 { 02722 TRACE("Passing to container.\n"); 02723 wined3d_texture_set_dirty(surface->container.u.texture, TRUE); 02724 } 02725 } 02726 02727 HRESULT surface_load(struct wined3d_surface *surface, BOOL srgb) 02728 { 02729 DWORD flag = srgb ? SFLAG_INSRGBTEX : SFLAG_INTEXTURE; 02730 BOOL ck_changed; 02731 02732 TRACE("surface %p, srgb %#x.\n", surface, srgb); 02733 02734 if (surface->resource.pool == WINED3D_POOL_SCRATCH) 02735 { 02736 ERR("Not supported on scratch surfaces.\n"); 02737 return WINED3DERR_INVALIDCALL; 02738 } 02739 02740 ck_changed = !(surface->flags & SFLAG_GLCKEY) != !(surface->CKeyFlags & WINEDDSD_CKSRCBLT); 02741 02742 /* Reload if either the texture and sysmem have different ideas about the 02743 * color key, or the actual key values changed. */ 02744 if (ck_changed || ((surface->CKeyFlags & WINEDDSD_CKSRCBLT) 02745 && (surface->gl_color_key.color_space_low_value != surface->src_blt_color_key.color_space_low_value 02746 || surface->gl_color_key.color_space_high_value != surface->src_blt_color_key.color_space_high_value))) 02747 { 02748 TRACE("Reloading because of color keying\n"); 02749 /* To perform the color key conversion we need a sysmem copy of 02750 * the surface. Make sure we have it. */ 02751 02752 surface_load_location(surface, SFLAG_INSYSMEM, NULL); 02753 /* Make sure the texture is reloaded because of the color key change, 02754 * this kills performance though :( */ 02755 /* TODO: This is not necessarily needed with hw palettized texture support. */ 02756 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE); 02757 /* Switching color keying on / off may change the internal format. */ 02758 if (ck_changed) 02759 surface_force_reload(surface); 02760 } 02761 else if (!(surface->flags & flag)) 02762 { 02763 TRACE("Reloading because surface is dirty.\n"); 02764 } 02765 else 02766 { 02767 TRACE("surface is already in texture\n"); 02768 return WINED3D_OK; 02769 } 02770 02771 /* No partial locking for textures yet. */ 02772 surface_load_location(surface, flag, NULL); 02773 surface_evict_sysmem(surface); 02774 02775 return WINED3D_OK; 02776 } 02777 02778 /* See also float_16_to_32() in wined3d_private.h */ 02779 static inline unsigned short float_32_to_16(const float *in) 02780 { 02781 int exp = 0; 02782 float tmp = fabsf(*in); 02783 unsigned int mantissa; 02784 unsigned short ret; 02785 02786 /* Deal with special numbers */ 02787 if (*in == 0.0f) 02788 return 0x0000; 02789 if (isnan(*in)) 02790 return 0x7c01; 02791 if (isinf(*in)) 02792 return (*in < 0.0f ? 0xfc00 : 0x7c00); 02793 02794 if (tmp < powf(2, 10)) 02795 { 02796 do 02797 { 02798 tmp = tmp * 2.0f; 02799 exp--; 02800 } while (tmp < powf(2, 10)); 02801 } 02802 else if (tmp >= powf(2, 11)) 02803 { 02804 do 02805 { 02806 tmp /= 2.0f; 02807 exp++; 02808 } while (tmp >= powf(2, 11)); 02809 } 02810 02811 mantissa = (unsigned int)tmp; 02812 if (tmp - mantissa >= 0.5f) 02813 ++mantissa; /* Round to nearest, away from zero. */ 02814 02815 exp += 10; /* Normalize the mantissa. */ 02816 exp += 15; /* Exponent is encoded with excess 15. */ 02817 02818 if (exp > 30) /* too big */ 02819 { 02820 ret = 0x7c00; /* INF */ 02821 } 02822 else if (exp <= 0) 02823 { 02824 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers. */ 02825 while (exp <= 0) 02826 { 02827 mantissa = mantissa >> 1; 02828 ++exp; 02829 } 02830 ret = mantissa & 0x3ff; 02831 } 02832 else 02833 { 02834 ret = (exp << 10) | (mantissa & 0x3ff); 02835 } 02836 02837 ret |= ((*in < 0.0f ? 1 : 0) << 15); /* Add the sign */ 02838 return ret; 02839 } 02840 02841 ULONG CDECL wined3d_surface_incref(struct wined3d_surface *surface) 02842 { 02843 ULONG refcount; 02844 02845 TRACE("Surface %p, container %p of type %#x.\n", 02846 surface, surface->container.u.base, surface->container.type); 02847 02848 switch (surface->container.type) 02849 { 02850 case WINED3D_CONTAINER_TEXTURE: 02851 return wined3d_texture_incref(surface->container.u.texture); 02852 02853 case WINED3D_CONTAINER_SWAPCHAIN: 02854 return wined3d_swapchain_incref(surface->container.u.swapchain); 02855 02856 default: 02857 ERR("Unhandled container type %#x.\n", surface->container.type); 02858 case WINED3D_CONTAINER_NONE: 02859 break; 02860 } 02861 02862 refcount = InterlockedIncrement(&surface->resource.ref); 02863 TRACE("%p increasing refcount to %u.\n", surface, refcount); 02864 02865 return refcount; 02866 } 02867 02868 /* Do not call while under the GL lock. */ 02869 ULONG CDECL wined3d_surface_decref(struct wined3d_surface *surface) 02870 { 02871 ULONG refcount; 02872 02873 TRACE("Surface %p, container %p of type %#x.\n", 02874 surface, surface->container.u.base, surface->container.type); 02875 02876 switch (surface->container.type) 02877 { 02878 case WINED3D_CONTAINER_TEXTURE: 02879 return wined3d_texture_decref(surface->container.u.texture); 02880 02881 case WINED3D_CONTAINER_SWAPCHAIN: 02882 return wined3d_swapchain_decref(surface->container.u.swapchain); 02883 02884 default: 02885 ERR("Unhandled container type %#x.\n", surface->container.type); 02886 case WINED3D_CONTAINER_NONE: 02887 break; 02888 } 02889 02890 refcount = InterlockedDecrement(&surface->resource.ref); 02891 TRACE("%p decreasing refcount to %u.\n", surface, refcount); 02892 02893 if (!refcount) 02894 { 02895 surface_cleanup(surface); 02896 surface->resource.parent_ops->wined3d_object_destroyed(surface->resource.parent); 02897 02898 TRACE("Destroyed surface %p.\n", surface); 02899 HeapFree(GetProcessHeap(), 0, surface); 02900 } 02901 02902 return refcount; 02903 } 02904 02905 DWORD CDECL wined3d_surface_set_priority(struct wined3d_surface *surface, DWORD priority) 02906 { 02907 return resource_set_priority(&surface->resource, priority); 02908 } 02909 02910 DWORD CDECL wined3d_surface_get_priority(const struct wined3d_surface *surface) 02911 { 02912 return resource_get_priority(&surface->resource); 02913 } 02914 02915 void CDECL wined3d_surface_preload(struct wined3d_surface *surface) 02916 { 02917 TRACE("surface %p.\n", surface); 02918 02919 if (!surface->resource.device->d3d_initialized) 02920 { 02921 ERR("D3D not initialized.\n"); 02922 return; 02923 } 02924 02925 surface_internal_preload(surface, SRGB_ANY); 02926 } 02927 02928 void * CDECL wined3d_surface_get_parent(const struct wined3d_surface *surface) 02929 { 02930 TRACE("surface %p.\n", surface); 02931 02932 return surface->resource.parent; 02933 } 02934 02935 struct wined3d_resource * CDECL wined3d_surface_get_resource(struct wined3d_surface *surface) 02936 { 02937 TRACE("surface %p.\n", surface); 02938 02939 return &surface->resource; 02940 } 02941 02942 HRESULT CDECL wined3d_surface_get_blt_status(const struct wined3d_surface *surface, DWORD flags) 02943 { 02944 TRACE("surface %p, flags %#x.\n", surface, flags); 02945 02946 switch (flags) 02947 { 02948 case WINEDDGBS_CANBLT: 02949 case WINEDDGBS_ISBLTDONE: 02950 return WINED3D_OK; 02951 02952 default: 02953 return WINED3DERR_INVALIDCALL; 02954 } 02955 } 02956 02957 HRESULT CDECL wined3d_surface_get_flip_status(const struct wined3d_surface *surface, DWORD flags) 02958 { 02959 TRACE("surface %p, flags %#x.\n", surface, flags); 02960 02961 /* XXX: DDERR_INVALIDSURFACETYPE */ 02962 02963 switch (flags) 02964 { 02965 case WINEDDGFS_CANFLIP: 02966 case WINEDDGFS_ISFLIPDONE: 02967 return WINED3D_OK; 02968 02969 default: 02970 return WINED3DERR_INVALIDCALL; 02971 } 02972 } 02973 02974 HRESULT CDECL wined3d_surface_is_lost(const struct wined3d_surface *surface) 02975 { 02976 TRACE("surface %p.\n", surface); 02977 02978 /* D3D8 and 9 loose full devices, ddraw only surfaces. */ 02979 return surface->flags & SFLAG_LOST ? WINED3DERR_DEVICELOST : WINED3D_OK; 02980 } 02981 02982 HRESULT CDECL wined3d_surface_restore(struct wined3d_surface *surface) 02983 { 02984 TRACE("surface %p.\n", surface); 02985 02986 surface->flags &= ~SFLAG_LOST; 02987 return WINED3D_OK; 02988 } 02989 02990 HRESULT CDECL wined3d_surface_set_palette(struct wined3d_surface *surface, struct wined3d_palette *palette) 02991 { 02992 TRACE("surface %p, palette %p.\n", surface, palette); 02993 02994 if (surface->palette == palette) 02995 { 02996 TRACE("Nop palette change.\n"); 02997 return WINED3D_OK; 02998 } 02999 03000 if (surface->palette && (surface->resource.usage & WINED3DUSAGE_RENDERTARGET)) 03001 surface->palette->flags &= ~WINEDDPCAPS_PRIMARYSURFACE; 03002 03003 surface->palette = palette; 03004 03005 if (palette) 03006 { 03007 if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET) 03008 palette->flags |= WINEDDPCAPS_PRIMARYSURFACE; 03009 03010 surface->surface_ops->surface_realize_palette(surface); 03011 } 03012 03013 return WINED3D_OK; 03014 } 03015 03016 HRESULT CDECL wined3d_surface_set_color_key(struct wined3d_surface *surface, 03017 DWORD flags, const struct wined3d_color_key *color_key) 03018 { 03019 TRACE("surface %p, flags %#x, color_key %p.\n", surface, flags, color_key); 03020 03021 if (flags & WINEDDCKEY_COLORSPACE) 03022 { 03023 FIXME(" colorkey value not supported (%08x) !\n", flags); 03024 return WINED3DERR_INVALIDCALL; 03025 } 03026 03027 /* Dirtify the surface, but only if a key was changed. */ 03028 if (color_key) 03029 { 03030 switch (flags & ~WINEDDCKEY_COLORSPACE) 03031 { 03032 case WINEDDCKEY_DESTBLT: 03033 surface->dst_blt_color_key = *color_key; 03034 surface->CKeyFlags |= WINEDDSD_CKDESTBLT; 03035 break; 03036 03037 case WINEDDCKEY_DESTOVERLAY: 03038 surface->dst_overlay_color_key = *color_key; 03039 surface->CKeyFlags |= WINEDDSD_CKDESTOVERLAY; 03040 break; 03041 03042 case WINEDDCKEY_SRCOVERLAY: 03043 surface->src_overlay_color_key = *color_key; 03044 surface->CKeyFlags |= WINEDDSD_CKSRCOVERLAY; 03045 break; 03046 03047 case WINEDDCKEY_SRCBLT: 03048 surface->src_blt_color_key = *color_key; 03049 surface->CKeyFlags |= WINEDDSD_CKSRCBLT; 03050 break; 03051 } 03052 } 03053 else 03054 { 03055 switch (flags & ~WINEDDCKEY_COLORSPACE) 03056 { 03057 case WINEDDCKEY_DESTBLT: 03058 surface->CKeyFlags &= ~WINEDDSD_CKDESTBLT; 03059 break; 03060 03061 case WINEDDCKEY_DESTOVERLAY: 03062 surface->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY; 03063 break; 03064 03065 case WINEDDCKEY_SRCOVERLAY: 03066 surface->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY; 03067 break; 03068 03069 case WINEDDCKEY_SRCBLT: 03070 surface->CKeyFlags &= ~WINEDDSD_CKSRCBLT; 03071 break; 03072 } 03073 } 03074 03075 return WINED3D_OK; 03076 } 03077 03078 struct wined3d_palette * CDECL wined3d_surface_get_palette(const struct wined3d_surface *surface) 03079 { 03080 TRACE("surface %p.\n", surface); 03081 03082 return surface->palette; 03083 } 03084 03085 DWORD CDECL wined3d_surface_get_pitch(const struct wined3d_surface *surface) 03086 { 03087 const struct wined3d_format *format = surface->resource.format; 03088 DWORD pitch; 03089 03090 TRACE("surface %p.\n", surface); 03091 03092 if (format->flags & WINED3DFMT_FLAG_BLOCKS) 03093 { 03094 /* Since compressed formats are block based, pitch means the amount of 03095 * bytes to the next row of block rather than the next row of pixels. */ 03096 UINT row_block_count = (surface->resource.width + format->block_width - 1) / format->block_width; 03097 pitch = row_block_count * format->block_byte_count; 03098 } 03099 else 03100 { 03101 unsigned char alignment = surface->resource.device->surface_alignment; 03102 pitch = surface->resource.format->byte_count * surface->resource.width; /* Bytes / row */ 03103 pitch = (pitch + alignment - 1) & ~(alignment - 1); 03104 } 03105 03106 TRACE("Returning %u.\n", pitch); 03107 03108 return pitch; 03109 } 03110 03111 HRESULT CDECL wined3d_surface_set_mem(struct wined3d_surface *surface, void *mem) 03112 { 03113 TRACE("surface %p, mem %p.\n", surface, mem); 03114 03115 if (surface->flags & (SFLAG_LOCKED | SFLAG_DCINUSE)) 03116 { 03117 WARN("Surface is locked or the DC is in use.\n"); 03118 return WINED3DERR_INVALIDCALL; 03119 } 03120 03121 /* Render targets depend on their hdc, and we can't create an hdc on a user pointer. */ 03122 if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET) 03123 { 03124 ERR("Not supported on render targets.\n"); 03125 return WINED3DERR_INVALIDCALL; 03126 } 03127 03128 if (mem && mem != surface->resource.allocatedMemory) 03129 { 03130 void *release = NULL; 03131 03132 /* Do I have to copy the old surface content? */ 03133 if (surface->flags & SFLAG_DIBSECTION) 03134 { 03135 DeleteDC(surface->hDC); 03136 DeleteObject(surface->dib.DIBsection); 03137 surface->dib.bitmap_data = NULL; 03138 surface->resource.allocatedMemory = NULL; 03139 surface->hDC = NULL; 03140 surface->flags &= ~SFLAG_DIBSECTION; 03141 } 03142 else if (!(surface->flags & SFLAG_USERPTR)) 03143 { 03144 release = surface->resource.heapMemory; 03145 surface->resource.heapMemory = NULL; 03146 } 03147 surface->resource.allocatedMemory = mem; 03148 surface->flags |= SFLAG_USERPTR; 03149 03150 /* Now the surface memory is most up do date. Invalidate drawable and texture. */ 03151 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE); 03152 03153 /* For client textures OpenGL has to be notified. */ 03154 if (surface->flags & SFLAG_CLIENT) 03155 surface_release_client_storage(surface); 03156 03157 /* Now free the old memory if any. */ 03158 HeapFree(GetProcessHeap(), 0, release); 03159 } 03160 else if (surface->flags & SFLAG_USERPTR) 03161 { 03162 /* HeapMemory should be NULL already. */ 03163 if (surface->resource.heapMemory) 03164 ERR("User pointer surface has heap memory allocated.\n"); 03165 03166 if (!mem) 03167 { 03168 surface->resource.allocatedMemory = NULL; 03169 surface->flags &= ~(SFLAG_USERPTR | SFLAG_INSYSMEM); 03170 03171 if (surface->flags & SFLAG_CLIENT) 03172 surface_release_client_storage(surface); 03173 03174 surface_prepare_system_memory(surface); 03175 } 03176 03177 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE); 03178 } 03179 03180 return WINED3D_OK; 03181 } 03182 03183 HRESULT CDECL wined3d_surface_set_overlay_position(struct wined3d_surface *surface, LONG x, LONG y) 03184 { 03185 LONG w, h; 03186 03187 TRACE("surface %p, x %d, y %d.\n", surface, x, y); 03188 03189 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY)) 03190 { 03191 WARN("Not an overlay surface.\n"); 03192 return WINEDDERR_NOTAOVERLAYSURFACE; 03193 } 03194 03195 w = surface->overlay_destrect.right - surface->overlay_destrect.left; 03196 h = surface->overlay_destrect.bottom - surface->overlay_destrect.top; 03197 surface->overlay_destrect.left = x; 03198 surface->overlay_destrect.top = y; 03199 surface->overlay_destrect.right = x + w; 03200 surface->overlay_destrect.bottom = y + h; 03201 03202 surface_draw_overlay(surface); 03203 03204 return WINED3D_OK; 03205 } 03206 03207 HRESULT CDECL wined3d_surface_get_overlay_position(const struct wined3d_surface *surface, LONG *x, LONG *y) 03208 { 03209 TRACE("surface %p, x %p, y %p.\n", surface, x, y); 03210 03211 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY)) 03212 { 03213 TRACE("Not an overlay surface.\n"); 03214 return WINEDDERR_NOTAOVERLAYSURFACE; 03215 } 03216 03217 if (!surface->overlay_dest) 03218 { 03219 TRACE("Overlay not visible.\n"); 03220 *x = 0; 03221 *y = 0; 03222 return WINEDDERR_OVERLAYNOTVISIBLE; 03223 } 03224 03225 *x = surface->overlay_destrect.left; 03226 *y = surface->overlay_destrect.top; 03227 03228 TRACE("Returning position %d, %d.\n", *x, *y); 03229 03230 return WINED3D_OK; 03231 } 03232 03233 HRESULT CDECL wined3d_surface_update_overlay_z_order(struct wined3d_surface *surface, 03234 DWORD flags, struct wined3d_surface *ref) 03235 { 03236 FIXME("surface %p, flags %#x, ref %p stub!\n", surface, flags, ref); 03237 03238 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY)) 03239 { 03240 TRACE("Not an overlay surface.\n"); 03241 return WINEDDERR_NOTAOVERLAYSURFACE; 03242 } 03243 03244 return WINED3D_OK; 03245 } 03246 03247 HRESULT CDECL wined3d_surface_update_overlay(struct wined3d_surface *surface, const RECT *src_rect, 03248 struct wined3d_surface *dst_surface, const RECT *dst_rect, DWORD flags, const WINEDDOVERLAYFX *fx) 03249 { 03250 TRACE("surface %p, src_rect %s, dst_surface %p, dst_rect %s, flags %#x, fx %p.\n", 03251 surface, wine_dbgstr_rect(src_rect), dst_surface, wine_dbgstr_rect(dst_rect), flags, fx); 03252 03253 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY)) 03254 { 03255 WARN("Not an overlay surface.\n"); 03256 return WINEDDERR_NOTAOVERLAYSURFACE; 03257 } 03258 else if (!dst_surface) 03259 { 03260 WARN("Dest surface is NULL.\n"); 03261 return WINED3DERR_INVALIDCALL; 03262 } 03263 03264 if (src_rect) 03265 { 03266 surface->overlay_srcrect = *src_rect; 03267 } 03268 else 03269 { 03270 surface->overlay_srcrect.left = 0; 03271 surface->overlay_srcrect.top = 0; 03272 surface->overlay_srcrect.right = surface->resource.width; 03273 surface->overlay_srcrect.bottom = surface->resource.height; 03274 } 03275 03276 if (dst_rect) 03277 { 03278 surface->overlay_destrect = *dst_rect; 03279 } 03280 else 03281 { 03282 surface->overlay_destrect.left = 0; 03283 surface->overlay_destrect.top = 0; 03284 surface->overlay_destrect.right = dst_surface ? dst_surface->resource.width : 0; 03285 surface->overlay_destrect.bottom = dst_surface ? dst_surface->resource.height : 0; 03286 } 03287 03288 if (surface->overlay_dest && (surface->overlay_dest != dst_surface || flags & WINEDDOVER_HIDE)) 03289 { 03290 surface->overlay_dest = NULL; 03291 list_remove(&surface->overlay_entry); 03292 } 03293 03294 if (flags & WINEDDOVER_SHOW) 03295 { 03296 if (surface->overlay_dest != dst_surface) 03297 { 03298 surface->overlay_dest = dst_surface; 03299 list_add_tail(&dst_surface->overlays, &surface->overlay_entry); 03300 } 03301 } 03302 else if (flags & WINEDDOVER_HIDE) 03303 { 03304 /* tests show that the rectangles are erased on hide */ 03305 surface->overlay_srcrect.left = 0; surface->overlay_srcrect.top = 0; 03306 surface->overlay_srcrect.right = 0; surface->overlay_srcrect.bottom = 0; 03307 surface->overlay_destrect.left = 0; surface->overlay_destrect.top = 0; 03308 surface->overlay_destrect.right = 0; surface->overlay_destrect.bottom = 0; 03309 surface->overlay_dest = NULL; 03310 } 03311 03312 surface_draw_overlay(surface); 03313 03314 return WINED3D_OK; 03315 } 03316 03317 HRESULT CDECL wined3d_surface_update_desc(struct wined3d_surface *surface, 03318 UINT width, UINT height, enum wined3d_format_id format_id, 03319 enum wined3d_multisample_type multisample_type, UINT multisample_quality) 03320 { 03321 struct wined3d_device *device = surface->resource.device; 03322 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; 03323 const struct wined3d_format *format = wined3d_get_format(gl_info, format_id); 03324 UINT resource_size = wined3d_format_calculate_size(format, device->surface_alignment, width, height); 03325 03326 TRACE("surface %p, width %u, height %u, format %s, multisample_type %#x, multisample_quality %u.\n", 03327 surface, width, height, debug_d3dformat(format_id), multisample_type, multisample_type); 03328 03329 if (!resource_size) 03330 return WINED3DERR_INVALIDCALL; 03331 03332 if (device->d3d_initialized) 03333 surface->resource.resource_ops->resource_unload(&surface->resource); 03334 03335 if (surface->flags & SFLAG_DIBSECTION) 03336 { 03337 DeleteDC(surface->hDC); 03338 DeleteObject(surface->dib.DIBsection); 03339 surface->dib.bitmap_data = NULL; 03340 surface->flags &= ~SFLAG_DIBSECTION; 03341 } 03342 03343 surface->flags &= ~(SFLAG_LOCATIONS | SFLAG_USERPTR); 03344 surface->resource.allocatedMemory = NULL; 03345 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory); 03346 surface->resource.heapMemory = NULL; 03347 03348 surface->resource.width = width; 03349 surface->resource.height = height; 03350 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE] 03351 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT]) 03352 { 03353 surface->pow2Width = width; 03354 surface->pow2Height = height; 03355 } 03356 else 03357 { 03358 surface->pow2Width = surface->pow2Height = 1; 03359 while (surface->pow2Width < width) 03360 surface->pow2Width <<= 1; 03361 while (surface->pow2Height < height) 03362 surface->pow2Height <<= 1; 03363 } 03364 03365 if (surface->pow2Width != width || surface->pow2Height != height) 03366 surface->flags |= SFLAG_NONPOW2; 03367 else 03368 surface->flags &= ~SFLAG_NONPOW2; 03369 03370 surface->resource.format = format; 03371 surface->resource.multisample_type = multisample_type; 03372 surface->resource.multisample_quality = multisample_quality; 03373 surface->resource.size = resource_size; 03374 03375 if (!surface_init_sysmem(surface)) 03376 return E_OUTOFMEMORY; 03377 03378 return WINED3D_OK; 03379 } 03380 03381 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst, 03382 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h) 03383 { 03384 unsigned short *dst_s; 03385 const float *src_f; 03386 unsigned int x, y; 03387 03388 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out); 03389 03390 for (y = 0; y < h; ++y) 03391 { 03392 src_f = (const float *)(src + y * pitch_in); 03393 dst_s = (unsigned short *) (dst + y * pitch_out); 03394 for (x = 0; x < w; ++x) 03395 { 03396 dst_s[x] = float_32_to_16(src_f + x); 03397 } 03398 } 03399 } 03400 03401 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst, 03402 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h) 03403 { 03404 static const unsigned char convert_5to8[] = 03405 { 03406 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a, 03407 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b, 03408 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd, 03409 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff, 03410 }; 03411 static const unsigned char convert_6to8[] = 03412 { 03413 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c, 03414 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d, 03415 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d, 03416 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d, 03417 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e, 03418 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe, 03419 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf, 03420 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff, 03421 }; 03422 unsigned int x, y; 03423 03424 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out); 03425 03426 for (y = 0; y < h; ++y) 03427 { 03428 const WORD *src_line = (const WORD *)(src + y * pitch_in); 03429 DWORD *dst_line = (DWORD *)(dst + y * pitch_out); 03430 for (x = 0; x < w; ++x) 03431 { 03432 WORD pixel = src_line[x]; 03433 dst_line[x] = 0xff000000 03434 | convert_5to8[(pixel & 0xf800) >> 11] << 16 03435 | convert_6to8[(pixel & 0x07e0) >> 5] << 8 03436 | convert_5to8[(pixel & 0x001f)]; 03437 } 03438 } 03439 } 03440 03441 /* We use this for both B8G8R8A8 -> B8G8R8X8 and B8G8R8X8 -> B8G8R8A8, since 03442 * in both cases we're just setting the X / Alpha channel to 0xff. */ 03443 static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst, 03444 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h) 03445 { 03446 unsigned int x, y; 03447 03448 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out); 03449 03450 for (y = 0; y < h; ++y) 03451 { 03452 const DWORD *src_line = (const DWORD *)(src + y * pitch_in); 03453 DWORD *dst_line = (DWORD *)(dst + y * pitch_out); 03454 03455 for (x = 0; x < w; ++x) 03456 { 03457 dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff); 03458 } 03459 } 03460 } 03461 03462 static inline BYTE cliptobyte(int x) 03463 { 03464 return (BYTE)((x < 0) ? 0 : ((x > 255) ? 255 : x)); 03465 } 03466 03467 static void convert_yuy2_x8r8g8b8(const BYTE *src, BYTE *dst, 03468 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h) 03469 { 03470 int c2, d, e, r2 = 0, g2 = 0, b2 = 0; 03471 unsigned int x, y; 03472 03473 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out); 03474 03475 for (y = 0; y < h; ++y) 03476 { 03477 const BYTE *src_line = src + y * pitch_in; 03478 DWORD *dst_line = (DWORD *)(dst + y * pitch_out); 03479 for (x = 0; x < w; ++x) 03480 { 03481 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV: 03482 * C = Y - 16; D = U - 128; E = V - 128; 03483 * R = cliptobyte((298 * C + 409 * E + 128) >> 8); 03484 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8); 03485 * B = cliptobyte((298 * C + 516 * D + 128) >> 8); 03486 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V . 03487 * U and V are shared between the pixels. */ 03488 if (!(x & 1)) /* For every even pixel, read new U and V. */ 03489 { 03490 d = (int) src_line[1] - 128; 03491 e = (int) src_line[3] - 128; 03492 r2 = 409 * e + 128; 03493 g2 = - 100 * d - 208 * e + 128; 03494 b2 = 516 * d + 128; 03495 } 03496 c2 = 298 * ((int) src_line[0] - 16); 03497 dst_line[x] = 0xff000000 03498 | cliptobyte((c2 + r2) >> 8) << 16 /* red */ 03499 | cliptobyte((c2 + g2) >> 8) << 8 /* green */ 03500 | cliptobyte((c2 + b2) >> 8); /* blue */ 03501 /* Scale RGB values to 0..255 range, 03502 * then clip them if still not in range (may be negative), 03503 * then shift them within DWORD if necessary. */ 03504 src_line += 2; 03505 } 03506 } 03507 } 03508 03509 static void convert_yuy2_r5g6b5(const BYTE *src, BYTE *dst, 03510 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h) 03511 { 03512 unsigned int x, y; 03513 int c2, d, e, r2 = 0, g2 = 0, b2 = 0; 03514 03515 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out); 03516 03517 for (y = 0; y < h; ++y) 03518 { 03519 const BYTE *src_line = src + y * pitch_in; 03520 WORD *dst_line = (WORD *)(dst + y * pitch_out); 03521 for (x = 0; x < w; ++x) 03522 { 03523 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV: 03524 * C = Y - 16; D = U - 128; E = V - 128; 03525 * R = cliptobyte((298 * C + 409 * E + 128) >> 8); 03526 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8); 03527 * B = cliptobyte((298 * C + 516 * D + 128) >> 8); 03528 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V . 03529 * U and V are shared between the pixels. */ 03530 if (!(x & 1)) /* For every even pixel, read new U and V. */ 03531 { 03532 d = (int) src_line[1] - 128; 03533 e = (int) src_line[3] - 128; 03534 r2 = 409 * e + 128; 03535 g2 = - 100 * d - 208 * e + 128; 03536 b2 = 516 * d + 128; 03537 } 03538 c2 = 298 * ((int) src_line[0] - 16); 03539 dst_line[x] = (cliptobyte((c2 + r2) >> 8) >> 3) << 11 /* red */ 03540 | (cliptobyte((c2 + g2) >> 8) >> 2) << 5 /* green */ 03541 | (cliptobyte((c2 + b2) >> 8) >> 3); /* blue */ 03542 /* Scale RGB values to 0..255 range, 03543 * then clip them if still not in range (may be negative), 03544 * then shift them within DWORD if necessary. */ 03545 src_line += 2; 03546 } 03547 } 03548 } 03549 03550 struct d3dfmt_convertor_desc 03551 { 03552 enum wined3d_format_id from, to; 03553 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h); 03554 }; 03555 03556 static const struct d3dfmt_convertor_desc convertors[] = 03557 { 03558 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float}, 03559 {WINED3DFMT_B5G6R5_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_r5g6b5_x8r8g8b8}, 03560 {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_a8r8g8b8_x8r8g8b8}, 03561 {WINED3DFMT_B8G8R8X8_UNORM, WINED3DFMT_B8G8R8A8_UNORM, convert_a8r8g8b8_x8r8g8b8}, 03562 {WINED3DFMT_YUY2, WINED3DFMT_B8G8R8X8_UNORM, convert_yuy2_x8r8g8b8}, 03563 {WINED3DFMT_YUY2, WINED3DFMT_B5G6R5_UNORM, convert_yuy2_r5g6b5}, 03564 }; 03565 03566 static inline const struct d3dfmt_convertor_desc *find_convertor(enum wined3d_format_id from, 03567 enum wined3d_format_id to) 03568 { 03569 unsigned int i; 03570 03571 for (i = 0; i < (sizeof(convertors) / sizeof(*convertors)); ++i) 03572 { 03573 if (convertors[i].from == from && convertors[i].to == to) 03574 return &convertors[i]; 03575 } 03576 03577 return NULL; 03578 } 03579 03580 /***************************************************************************** 03581 * surface_convert_format 03582 * 03583 * Creates a duplicate of a surface in a different format. Is used by Blt to 03584 * blit between surfaces with different formats. 03585 * 03586 * Parameters 03587 * source: Source surface 03588 * fmt: Requested destination format 03589 * 03590 *****************************************************************************/ 03591 static struct wined3d_surface *surface_convert_format(struct wined3d_surface *source, enum wined3d_format_id to_fmt) 03592 { 03593 struct wined3d_mapped_rect src_map, dst_map; 03594 const struct d3dfmt_convertor_desc *conv; 03595 struct wined3d_surface *ret = NULL; 03596 HRESULT hr; 03597 03598 conv = find_convertor(source->resource.format->id, to_fmt); 03599 if (!conv) 03600 { 03601 FIXME("Cannot find a conversion function from format %s to %s.\n", 03602 debug_d3dformat(source->resource.format->id), debug_d3dformat(to_fmt)); 03603 return NULL; 03604 } 03605 03606 wined3d_surface_create(source->resource.device, source->resource.width, 03607 source->resource.height, to_fmt, 0 /* level */, 0 /* usage */, WINED3D_POOL_SCRATCH, 03608 WINED3D_MULTISAMPLE_NONE /* TODO: Multisampled conversion */, 0 /* MultiSampleQuality */, 03609 source->surface_type, WINED3D_SURFACE_MAPPABLE | WINED3D_SURFACE_DISCARD, 03610 NULL /* parent */, &wined3d_null_parent_ops, &ret); 03611 if (!ret) 03612 { 03613 ERR("Failed to create a destination surface for conversion.\n"); 03614 return NULL; 03615 } 03616 03617 memset(&src_map, 0, sizeof(src_map)); 03618 memset(&dst_map, 0, sizeof(dst_map)); 03619 03620 hr = wined3d_surface_map(source, &src_map, NULL, WINED3DLOCK_READONLY); 03621 if (FAILED(hr)) 03622 { 03623 ERR("Failed to lock the source surface.\n"); 03624 wined3d_surface_decref(ret); 03625 return NULL; 03626 } 03627 hr = wined3d_surface_map(ret, &dst_map, NULL, WINED3DLOCK_READONLY); 03628 if (FAILED(hr)) 03629 { 03630 ERR("Failed to lock the destination surface.\n"); 03631 wined3d_surface_unmap(source); 03632 wined3d_surface_decref(ret); 03633 return NULL; 03634 } 03635 03636 conv->convert(src_map.data, dst_map.data, src_map.row_pitch, dst_map.row_pitch, 03637 source->resource.width, source->resource.height); 03638 03639 wined3d_surface_unmap(ret); 03640 wined3d_surface_unmap(source); 03641 03642 return ret; 03643 } 03644 03645 static HRESULT _Blt_ColorFill(BYTE *buf, unsigned int width, unsigned int height, 03646 unsigned int bpp, UINT pitch, DWORD color) 03647 { 03648 BYTE *first; 03649 int x, y; 03650 03651 /* Do first row */ 03652 03653 #define COLORFILL_ROW(type) \ 03654 do { \ 03655 type *d = (type *)buf; \ 03656 for (x = 0; x < width; ++x) \ 03657 d[x] = (type)color; \ 03658 } while(0) 03659 03660 switch (bpp) 03661 { 03662 case 1: 03663 COLORFILL_ROW(BYTE); 03664 break; 03665 03666 case 2: 03667 COLORFILL_ROW(WORD); 03668 break; 03669 03670 case 3: 03671 { 03672 BYTE *d = buf; 03673 for (x = 0; x < width; ++x, d += 3) 03674 { 03675 d[0] = (color ) & 0xFF; 03676 d[1] = (color >> 8) & 0xFF; 03677 d[2] = (color >> 16) & 0xFF; 03678 } 03679 break; 03680 } 03681 case 4: 03682 COLORFILL_ROW(DWORD); 03683 break; 03684 03685 default: 03686 FIXME("Color fill not implemented for bpp %u!\n", bpp * 8); 03687 return WINED3DERR_NOTAVAILABLE; 03688 } 03689 03690 #undef COLORFILL_ROW 03691 03692 /* Now copy first row. */ 03693 first = buf; 03694 for (y = 1; y < height; ++y) 03695 { 03696 buf += pitch; 03697 memcpy(buf, first, width * bpp); 03698 } 03699 03700 return WINED3D_OK; 03701 } 03702 03703 HRESULT CDECL wined3d_surface_unmap(struct wined3d_surface *surface) 03704 { 03705 TRACE("surface %p.\n", surface); 03706 03707 if (!(surface->flags & SFLAG_LOCKED)) 03708 { 03709 WARN("Trying to unmap unmapped surface.\n"); 03710 return WINEDDERR_NOTLOCKED; 03711 } 03712 surface->flags &= ~SFLAG_LOCKED; 03713 03714 surface->surface_ops->surface_unmap(surface); 03715 03716 return WINED3D_OK; 03717 } 03718 03719 HRESULT CDECL wined3d_surface_map(struct wined3d_surface *surface, 03720 struct wined3d_mapped_rect *mapped_rect, const RECT *rect, DWORD flags) 03721 { 03722 const struct wined3d_format *format = surface->resource.format; 03723 03724 TRACE("surface %p, mapped_rect %p, rect %s, flags %#x.\n", 03725 surface, mapped_rect, wine_dbgstr_rect(rect), flags); 03726 03727 if (surface->flags & SFLAG_LOCKED) 03728 { 03729 WARN("Surface is already mapped.\n"); 03730 return WINED3DERR_INVALIDCALL; 03731 } 03732 if ((format->flags & WINED3DFMT_FLAG_BLOCKS) 03733 && rect && (rect->left || rect->top 03734 || rect->right != surface->resource.width 03735 || rect->bottom != surface->resource.height)) 03736 { 03737 UINT width_mask = format->block_width - 1; 03738 UINT height_mask = format->block_height - 1; 03739 03740 if ((rect->left & width_mask) || (rect->right & width_mask) 03741 || (rect->top & height_mask) || (rect->bottom & height_mask)) 03742 { 03743 WARN("Map rect %s is misaligned for %ux%u blocks.\n", 03744 wine_dbgstr_rect(rect), format->block_width, format->block_height); 03745 03746 if (surface->resource.pool == WINED3D_POOL_DEFAULT) 03747 return WINED3DERR_INVALIDCALL; 03748 } 03749 } 03750 03751 surface->flags |= SFLAG_LOCKED; 03752 03753 if (!(surface->flags & SFLAG_LOCKABLE)) 03754 WARN("Trying to lock unlockable surface.\n"); 03755 03756 /* Performance optimization: Count how often a surface is mapped, if it is 03757 * mapped regularly do not throw away the system memory copy. This avoids 03758 * the need to download the surface from OpenGL all the time. The surface 03759 * is still downloaded if the OpenGL texture is changed. */ 03760 if (!(surface->flags & SFLAG_DYNLOCK)) 03761 { 03762 if (++surface->lockCount > MAXLOCKCOUNT) 03763 { 03764 TRACE("Surface is mapped regularly, not freeing the system memory copy any more.\n"); 03765 surface->flags |= SFLAG_DYNLOCK; 03766 } 03767 } 03768 03769 surface->surface_ops->surface_map(surface, rect, flags); 03770 03771 if (format->flags & WINED3DFMT_FLAG_BROKEN_PITCH) 03772 mapped_rect->row_pitch = surface->resource.width * format->byte_count; 03773 else 03774 mapped_rect->row_pitch = wined3d_surface_get_pitch(surface); 03775 03776 if (!rect) 03777 { 03778 mapped_rect->data = surface->resource.allocatedMemory; 03779 surface->lockedRect.left = 0; 03780 surface->lockedRect.top = 0; 03781 surface->lockedRect.right = surface->resource.width; 03782 surface->lockedRect.bottom = surface->resource.height; 03783 } 03784 else 03785 { 03786 if ((format->flags & (WINED3DFMT_FLAG_BLOCKS | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_BLOCKS) 03787 { 03788 /* Compressed textures are block based, so calculate the offset of 03789 * the block that contains the top-left pixel of the locked rectangle. */ 03790 mapped_rect->data = surface->resource.allocatedMemory 03791 + ((rect->top / format->block_height) * mapped_rect->row_pitch) 03792 + ((rect->left / format->block_width) * format->block_byte_count); 03793 } 03794 else 03795 { 03796 mapped_rect->data = surface->resource.allocatedMemory 03797 + (mapped_rect->row_pitch * rect->top) 03798 + (rect->left * format->byte_count); 03799 } 03800 surface->lockedRect.left = rect->left; 03801 surface->lockedRect.top = rect->top; 03802 surface->lockedRect.right = rect->right; 03803 surface->lockedRect.bottom = rect->bottom; 03804 } 03805 03806 TRACE("Locked rect %s.\n", wine_dbgstr_rect(&surface->lockedRect)); 03807 TRACE("Returning memory %p, pitch %u.\n", mapped_rect->data, mapped_rect->row_pitch); 03808 03809 return WINED3D_OK; 03810 } 03811 03812 HRESULT CDECL wined3d_surface_getdc(struct wined3d_surface *surface, HDC *dc) 03813 { 03814 struct wined3d_mapped_rect map; 03815 HRESULT hr; 03816 03817 TRACE("surface %p, dc %p.\n", surface, dc); 03818 03819 if (surface->flags & SFLAG_USERPTR) 03820 { 03821 ERR("Not supported on surfaces with application-provided memory.\n"); 03822 return WINEDDERR_NODC; 03823 } 03824 03825 /* Give more detailed info for ddraw. */ 03826 if (surface->flags & SFLAG_DCINUSE) 03827 return WINEDDERR_DCALREADYCREATED; 03828 03829 /* Can't GetDC if the surface is locked. */ 03830 if (surface->flags & SFLAG_LOCKED) 03831 return WINED3DERR_INVALIDCALL; 03832 03833 /* Create a DIB section if there isn't a dc yet. */ 03834 if (!surface->hDC) 03835 { 03836 if (surface->flags & SFLAG_CLIENT) 03837 { 03838 surface_load_location(surface, SFLAG_INSYSMEM, NULL); 03839 surface_release_client_storage(surface); 03840 } 03841 hr = surface_create_dib_section(surface); 03842 if (FAILED(hr)) 03843 return WINED3DERR_INVALIDCALL; 03844 03845 /* Use the DIB section from now on if we are not using a PBO. */ 03846 if (!(surface->flags & SFLAG_PBO)) 03847 surface->resource.allocatedMemory = surface->dib.bitmap_data; 03848 } 03849 03850 /* Map the surface. */ 03851 hr = wined3d_surface_map(surface, &map, NULL, 0); 03852 if (FAILED(hr)) 03853 { 03854 ERR("Map failed, hr %#x.\n", hr); 03855 return hr; 03856 } 03857 03858 /* Sync the DIB with the PBO. This can't be done earlier because Map() 03859 * activates the allocatedMemory. */ 03860 if (surface->flags & SFLAG_PBO) 03861 memcpy(surface->dib.bitmap_data, surface->resource.allocatedMemory, surface->resource.size); 03862 03863 if (surface->resource.format->id == WINED3DFMT_P8_UINT 03864 || surface->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM) 03865 { 03866 /* GetDC on palettized formats is unsupported in D3D9, and the method 03867 * is missing in D3D8, so this should only be used for DX <=7 03868 * surfaces (with non-device palettes). */ 03869 const PALETTEENTRY *pal = NULL; 03870 03871 if (surface->palette) 03872 { 03873 pal = surface->palette->palents; 03874 } 03875 else 03876 { 03877 struct wined3d_swapchain *swapchain = surface->resource.device->swapchains[0]; 03878 struct wined3d_surface *dds_primary = swapchain->front_buffer; 03879 03880 if (dds_primary && dds_primary->palette) 03881 pal = dds_primary->palette->palents; 03882 } 03883 03884 if (pal) 03885 { 03886 RGBQUAD col[256]; 03887 unsigned int i; 03888 03889 for (i = 0; i < 256; ++i) 03890 { 03891 col[i].rgbRed = pal[i].peRed; 03892 col[i].rgbGreen = pal[i].peGreen; 03893 col[i].rgbBlue = pal[i].peBlue; 03894 col[i].rgbReserved = 0; 03895 } 03896 SetDIBColorTable(surface->hDC, 0, 256, col); 03897 } 03898 } 03899 03900 surface->flags |= SFLAG_DCINUSE; 03901 03902 *dc = surface->hDC; 03903 TRACE("Returning dc %p.\n", *dc); 03904 03905 return WINED3D_OK; 03906 } 03907 03908 HRESULT CDECL wined3d_surface_releasedc(struct wined3d_surface *surface, HDC dc) 03909 { 03910 TRACE("surface %p, dc %p.\n", surface, dc); 03911 03912 if (!(surface->flags & SFLAG_DCINUSE)) 03913 return WINEDDERR_NODC; 03914 03915 if (surface->hDC != dc) 03916 { 03917 WARN("Application tries to release invalid DC %p, surface DC is %p.\n", 03918 dc, surface->hDC); 03919 return WINEDDERR_NODC; 03920 } 03921 03922 /* Copy the contents of the DIB over to the PBO. */ 03923 if ((surface->flags & SFLAG_PBO) && surface->resource.allocatedMemory) 03924 memcpy(surface->resource.allocatedMemory, surface->dib.bitmap_data, surface->resource.size); 03925 03926 /* We locked first, so unlock now. */ 03927 wined3d_surface_unmap(surface); 03928 03929 surface->flags &= ~SFLAG_DCINUSE; 03930 03931 return WINED3D_OK; 03932 } 03933 03934 HRESULT CDECL wined3d_surface_flip(struct wined3d_surface *surface, struct wined3d_surface *override, DWORD flags) 03935 { 03936 TRACE("surface %p, override %p, flags %#x.\n", surface, override, flags); 03937 03938 if (flags) 03939 { 03940 static UINT once; 03941 if (!once++) 03942 FIXME("Ignoring flags %#x.\n", flags); 03943 else 03944 WARN("Ignoring flags %#x.\n", flags); 03945 } 03946 03947 if (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN) 03948 { 03949 ERR("Not supported on swapchain surfaces.\n"); 03950 return WINEDDERR_NOTFLIPPABLE; 03951 } 03952 03953 /* Flipping is only supported on render targets and overlays. */ 03954 if (!(surface->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_OVERLAY))) 03955 { 03956 WARN("Tried to flip a non-render target, non-overlay surface.\n"); 03957 return WINEDDERR_NOTFLIPPABLE; 03958 } 03959 03960 flip_surface(surface, override); 03961 03962 /* Update overlays if they're visible. */ 03963 if ((surface->resource.usage & WINED3DUSAGE_OVERLAY) && surface->overlay_dest) 03964 return surface_draw_overlay(surface); 03965 03966 return WINED3D_OK; 03967 } 03968 03969 /* Do not call while under the GL lock. */ 03970 void surface_internal_preload(struct wined3d_surface *surface, enum WINED3DSRGB srgb) 03971 { 03972 struct wined3d_device *device = surface->resource.device; 03973 03974 TRACE("iface %p, srgb %#x.\n", surface, srgb); 03975 03976 if (surface->container.type == WINED3D_CONTAINER_TEXTURE) 03977 { 03978 struct wined3d_texture *texture = surface->container.u.texture; 03979 03980 TRACE("Passing to container (%p).\n", texture); 03981 texture->texture_ops->texture_preload(texture, srgb); 03982 } 03983 else 03984 { 03985 struct wined3d_context *context; 03986 03987 TRACE("(%p) : About to load surface\n", surface); 03988 03989 /* TODO: Use already acquired context when possible. */ 03990 context = context_acquire(device, NULL); 03991 03992 surface_load(surface, srgb == SRGB_SRGB ? TRUE : FALSE); 03993 03994 if (surface->resource.pool == WINED3D_POOL_DEFAULT) 03995 { 03996 /* Tell opengl to try and keep this texture in video ram (well mostly) */ 03997 GLclampf tmp; 03998 tmp = 0.9f; 03999 ENTER_GL(); 04000 glPrioritizeTextures(1, &surface->texture_name, &tmp); 04001 LEAVE_GL(); 04002 } 04003 04004 context_release(context); 04005 } 04006 } 04007 04008 BOOL surface_init_sysmem(struct wined3d_surface *surface) 04009 { 04010 if (!surface->resource.allocatedMemory) 04011 { 04012 if (!surface->resource.heapMemory) 04013 { 04014 if (!(surface->resource.heapMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 04015 surface->resource.size + RESOURCE_ALIGNMENT))) 04016 { 04017 ERR("Failed to allocate memory.\n"); 04018 return FALSE; 04019 } 04020 } 04021 else if (!(surface->flags & SFLAG_CLIENT)) 04022 { 04023 ERR("Surface %p has heapMemory %p and flags %#x.\n", 04024 surface, surface->resource.heapMemory, surface->flags); 04025 } 04026 04027 surface->resource.allocatedMemory = 04028 (BYTE *)(((ULONG_PTR)surface->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1)); 04029 } 04030 else 04031 { 04032 memset(surface->resource.allocatedMemory, 0, surface->resource.size); 04033 } 04034 04035 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE); 04036 04037 return TRUE; 04038 } 04039 04040 /* Read the framebuffer back into the surface */ 04041 static void read_from_framebuffer(struct wined3d_surface *surface, const RECT *rect, void *dest, UINT pitch) 04042 { 04043 struct wined3d_device *device = surface->resource.device; 04044 const struct wined3d_gl_info *gl_info; 04045 struct wined3d_context *context; 04046 BYTE *mem; 04047 GLint fmt; 04048 GLint type; 04049 BYTE *row, *top, *bottom; 04050 int i; 04051 BOOL bpp; 04052 RECT local_rect; 04053 BOOL srcIsUpsideDown; 04054 GLint rowLen = 0; 04055 GLint skipPix = 0; 04056 GLint skipRow = 0; 04057 04058 context = context_acquire(device, surface); 04059 context_apply_blit_state(context, device); 04060 gl_info = context->gl_info; 04061 04062 ENTER_GL(); 04063 04064 /* Select the correct read buffer, and give some debug output. 04065 * There is no need to keep track of the current read buffer or reset it, every part of the code 04066 * that reads sets the read buffer as desired. 04067 */ 04068 if (surface_is_offscreen(surface)) 04069 { 04070 /* Mapping the primary render target which is not on a swapchain. 04071 * Read from the back buffer. */ 04072 TRACE("Mapping offscreen render target.\n"); 04073 glReadBuffer(device->offscreenBuffer); 04074 srcIsUpsideDown = TRUE; 04075 } 04076 else 04077 { 04078 /* Onscreen surfaces are always part of a swapchain */ 04079 GLenum buffer = surface_get_gl_buffer(surface); 04080 TRACE("Mapping %#x buffer.\n", buffer); 04081 glReadBuffer(buffer); 04082 checkGLcall("glReadBuffer"); 04083 srcIsUpsideDown = FALSE; 04084 } 04085 04086 /* TODO: Get rid of the extra rectangle comparison and construction of a full surface rectangle */ 04087 if (!rect) 04088 { 04089 local_rect.left = 0; 04090 local_rect.top = 0; 04091 local_rect.right = surface->resource.width; 04092 local_rect.bottom = surface->resource.height; 04093 } 04094 else 04095 { 04096 local_rect = *rect; 04097 } 04098 /* TODO: Get rid of the extra GetPitch call, LockRect does that too. Cache the pitch */ 04099 04100 switch (surface->resource.format->id) 04101 { 04102 case WINED3DFMT_P8_UINT: 04103 { 04104 if (primary_render_target_is_p8(device)) 04105 { 04106 /* In case of P8 render targets the index is stored in the alpha component */ 04107 fmt = GL_ALPHA; 04108 type = GL_UNSIGNED_BYTE; 04109 mem = dest; 04110 bpp = surface->resource.format->byte_count; 04111 } 04112 else 04113 { 04114 /* GL can't return palettized data, so read ARGB pixels into a 04115 * separate block of memory and convert them into palettized format 04116 * in software. Slow, but if the app means to use palettized render 04117 * targets and locks it... 04118 * 04119 * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons 04120 * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out 04121 * for the color channels when palettizing the colors. 04122 */ 04123 fmt = GL_RGB; 04124 type = GL_UNSIGNED_BYTE; 04125 pitch *= 3; 04126 mem = HeapAlloc(GetProcessHeap(), 0, surface->resource.size * 3); 04127 if (!mem) 04128 { 04129 ERR("Out of memory\n"); 04130 LEAVE_GL(); 04131 return; 04132 } 04133 bpp = surface->resource.format->byte_count * 3; 04134 } 04135 } 04136 break; 04137 04138 default: 04139 mem = dest; 04140 fmt = surface->resource.format->glFormat; 04141 type = surface->resource.format->glType; 04142 bpp = surface->resource.format->byte_count; 04143 } 04144 04145 if (surface->flags & SFLAG_PBO) 04146 { 04147 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, surface->pbo)); 04148 checkGLcall("glBindBufferARB"); 04149 if (mem) 04150 { 04151 ERR("mem not null for pbo -- unexpected\n"); 04152 mem = NULL; 04153 } 04154 } 04155 04156 /* Save old pixel store pack state */ 04157 glGetIntegerv(GL_PACK_ROW_LENGTH, &rowLen); 04158 checkGLcall("glGetIntegerv"); 04159 glGetIntegerv(GL_PACK_SKIP_PIXELS, &skipPix); 04160 checkGLcall("glGetIntegerv"); 04161 glGetIntegerv(GL_PACK_SKIP_ROWS, &skipRow); 04162 checkGLcall("glGetIntegerv"); 04163 04164 /* Setup pixel store pack state -- to glReadPixels into the correct place */ 04165 glPixelStorei(GL_PACK_ROW_LENGTH, surface->resource.width); 04166 checkGLcall("glPixelStorei"); 04167 glPixelStorei(GL_PACK_SKIP_PIXELS, local_rect.left); 04168 checkGLcall("glPixelStorei"); 04169 glPixelStorei(GL_PACK_SKIP_ROWS, local_rect.top); 04170 checkGLcall("glPixelStorei"); 04171 04172 glReadPixels(local_rect.left, !srcIsUpsideDown ? (surface->resource.height - local_rect.bottom) : local_rect.top, 04173 local_rect.right - local_rect.left, 04174 local_rect.bottom - local_rect.top, 04175 fmt, type, mem); 04176 checkGLcall("glReadPixels"); 04177 04178 /* Reset previous pixel store pack state */ 04179 glPixelStorei(GL_PACK_ROW_LENGTH, rowLen); 04180 checkGLcall("glPixelStorei"); 04181 glPixelStorei(GL_PACK_SKIP_PIXELS, skipPix); 04182 checkGLcall("glPixelStorei"); 04183 glPixelStorei(GL_PACK_SKIP_ROWS, skipRow); 04184 checkGLcall("glPixelStorei"); 04185 04186 if (surface->flags & SFLAG_PBO) 04187 { 04188 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0)); 04189 checkGLcall("glBindBufferARB"); 04190 04191 /* Check if we need to flip the image. If we need to flip use glMapBufferARB 04192 * to get a pointer to it and perform the flipping in software. This is a lot 04193 * faster than calling glReadPixels for each line. In case we want more speed 04194 * we should rerender it flipped in a FBO and read the data back from the FBO. */ 04195 if (!srcIsUpsideDown) 04196 { 04197 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo)); 04198 checkGLcall("glBindBufferARB"); 04199 04200 mem = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB)); 04201 checkGLcall("glMapBufferARB"); 04202 } 04203 } 04204 04205 /* TODO: Merge this with the palettization loop below for P8 targets */ 04206 if(!srcIsUpsideDown) { 04207 UINT len, off; 04208 /* glReadPixels returns the image upside down, and there is no way to prevent this. 04209 Flip the lines in software */ 04210 len = (local_rect.right - local_rect.left) * bpp; 04211 off = local_rect.left * bpp; 04212 04213 row = HeapAlloc(GetProcessHeap(), 0, len); 04214 if(!row) { 04215 ERR("Out of memory\n"); 04216 if (surface->resource.format->id == WINED3DFMT_P8_UINT) 04217 HeapFree(GetProcessHeap(), 0, mem); 04218 LEAVE_GL(); 04219 return; 04220 } 04221 04222 top = mem + pitch * local_rect.top; 04223 bottom = mem + pitch * (local_rect.bottom - 1); 04224 for(i = 0; i < (local_rect.bottom - local_rect.top) / 2; i++) { 04225 memcpy(row, top + off, len); 04226 memcpy(top + off, bottom + off, len); 04227 memcpy(bottom + off, row, len); 04228 top += pitch; 04229 bottom -= pitch; 04230 } 04231 HeapFree(GetProcessHeap(), 0, row); 04232 04233 /* Unmap the temp PBO buffer */ 04234 if (surface->flags & SFLAG_PBO) 04235 { 04236 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB)); 04237 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0)); 04238 } 04239 } 04240 04241 LEAVE_GL(); 04242 context_release(context); 04243 04244 /* For P8 textures we need to perform an inverse palette lookup. This is 04245 * done by searching for a palette index which matches the RGB value. 04246 * Note this isn't guaranteed to work when there are multiple entries for 04247 * the same color but we have no choice. In case of P8 render targets, 04248 * the index is stored in the alpha component so no conversion is needed. */ 04249 if (surface->resource.format->id == WINED3DFMT_P8_UINT && !primary_render_target_is_p8(device)) 04250 { 04251 const PALETTEENTRY *pal = NULL; 04252 DWORD width = pitch / 3; 04253 int x, y, c; 04254 04255 if (surface->palette) 04256 { 04257 pal = surface->palette->palents; 04258 } 04259 else 04260 { 04261 ERR("Palette is missing, cannot perform inverse palette lookup\n"); 04262 HeapFree(GetProcessHeap(), 0, mem); 04263 return; 04264 } 04265 04266 for(y = local_rect.top; y < local_rect.bottom; y++) { 04267 for(x = local_rect.left; x < local_rect.right; x++) { 04268 /* start lines pixels */ 04269 const BYTE *blue = mem + y * pitch + x * (sizeof(BYTE) * 3); 04270 const BYTE *green = blue + 1; 04271 const BYTE *red = green + 1; 04272 04273 for(c = 0; c < 256; c++) { 04274 if(*red == pal[c].peRed && 04275 *green == pal[c].peGreen && 04276 *blue == pal[c].peBlue) 04277 { 04278 *((BYTE *) dest + y * width + x) = c; 04279 break; 04280 } 04281 } 04282 } 04283 } 04284 HeapFree(GetProcessHeap(), 0, mem); 04285 } 04286 } 04287 04288 /* Read the framebuffer contents into a texture. Note that this function 04289 * doesn't do any kind of flipping. Using this on an onscreen surface will 04290 * result in a flipped D3D texture. */ 04291 void surface_load_fb_texture(struct wined3d_surface *surface, BOOL srgb) 04292 { 04293 struct wined3d_device *device = surface->resource.device; 04294 struct wined3d_context *context; 04295 04296 context = context_acquire(device, surface); 04297 device_invalidate_state(device, STATE_FRAMEBUFFER); 04298 04299 surface_prepare_texture(surface, context, srgb); 04300 surface_bind_and_dirtify(surface, context, srgb); 04301 04302 TRACE("Reading back offscreen render target %p.\n", surface); 04303 04304 ENTER_GL(); 04305 04306 if (surface_is_offscreen(surface)) 04307 glReadBuffer(device->offscreenBuffer); 04308 else 04309 glReadBuffer(surface_get_gl_buffer(surface)); 04310 checkGLcall("glReadBuffer"); 04311 04312 glCopyTexSubImage2D(surface->texture_target, surface->texture_level, 04313 0, 0, 0, 0, surface->resource.width, surface->resource.height); 04314 checkGLcall("glCopyTexSubImage2D"); 04315 04316 LEAVE_GL(); 04317 04318 context_release(context); 04319 } 04320 04321 /* Context activation is done by the caller. */ 04322 static void surface_prepare_texture_internal(struct wined3d_surface *surface, 04323 struct wined3d_context *context, BOOL srgb) 04324 { 04325 DWORD alloc_flag = srgb ? SFLAG_SRGBALLOCATED : SFLAG_ALLOCATED; 04326 CONVERT_TYPES convert; 04327 struct wined3d_format format; 04328 04329 if (surface->flags & alloc_flag) return; 04330 04331 d3dfmt_get_conv(surface, TRUE, TRUE, &format, &convert); 04332 if (convert != NO_CONVERSION || format.convert) surface->flags |= SFLAG_CONVERTED; 04333 else surface->flags &= ~SFLAG_CONVERTED; 04334 04335 surface_bind_and_dirtify(surface, context, srgb); 04336 surface_allocate_surface(surface, context->gl_info, &format, srgb); 04337 surface->flags |= alloc_flag; 04338 } 04339 04340 /* Context activation is done by the caller. */ 04341 void surface_prepare_texture(struct wined3d_surface *surface, struct wined3d_context *context, BOOL srgb) 04342 { 04343 if (surface->container.type == WINED3D_CONTAINER_TEXTURE) 04344 { 04345 struct wined3d_texture *texture = surface->container.u.texture; 04346 UINT sub_count = texture->level_count * texture->layer_count; 04347 UINT i; 04348 04349 TRACE("surface %p is a subresource of texture %p.\n", surface, texture); 04350 04351 for (i = 0; i < sub_count; ++i) 04352 { 04353 struct wined3d_surface *s = surface_from_resource(texture->sub_resources[i]); 04354 surface_prepare_texture_internal(s, context, srgb); 04355 } 04356 04357 return; 04358 } 04359 04360 surface_prepare_texture_internal(surface, context, srgb); 04361 } 04362 04363 void surface_prepare_rb(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info, BOOL multisample) 04364 { 04365 if (multisample) 04366 { 04367 if (surface->rb_multisample) 04368 return; 04369 04370 gl_info->fbo_ops.glGenRenderbuffers(1, &surface->rb_multisample); 04371 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, surface->rb_multisample); 04372 gl_info->fbo_ops.glRenderbufferStorageMultisample(GL_RENDERBUFFER, surface->resource.multisample_type, 04373 surface->resource.format->glInternal, surface->pow2Width, surface->pow2Height); 04374 TRACE("Created multisample rb %u.\n", surface->rb_multisample); 04375 } 04376 else 04377 { 04378 if (surface->rb_resolved) 04379 return; 04380 04381 gl_info->fbo_ops.glGenRenderbuffers(1, &surface->rb_resolved); 04382 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, surface->rb_resolved); 04383 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER, surface->resource.format->glInternal, 04384 surface->pow2Width, surface->pow2Height); 04385 TRACE("Created resolved rb %u.\n", surface->rb_resolved); 04386 } 04387 } 04388 04389 static void flush_to_framebuffer_drawpixels(struct wined3d_surface *surface, 04390 const RECT *rect, GLenum fmt, GLenum type, UINT bpp, const BYTE *mem) 04391 { 04392 struct wined3d_device *device = surface->resource.device; 04393 UINT pitch = wined3d_surface_get_pitch(surface); 04394 const struct wined3d_gl_info *gl_info; 04395 struct wined3d_context *context; 04396 RECT local_rect; 04397 UINT w, h; 04398 04399 surface_get_rect(surface, rect, &local_rect); 04400 04401 mem += local_rect.top * pitch + local_rect.left * bpp; 04402 w = local_rect.right - local_rect.left; 04403 h = local_rect.bottom - local_rect.top; 04404 04405 /* Activate the correct context for the render target */ 04406 context = context_acquire(device, surface); 04407 context_apply_blit_state(context, device); 04408 gl_info = context->gl_info; 04409 04410 ENTER_GL(); 04411 04412 if (!surface_is_offscreen(surface)) 04413 { 04414 GLenum buffer = surface_get_gl_buffer(surface); 04415 TRACE("Unlocking %#x buffer.\n", buffer); 04416 context_set_draw_buffer(context, buffer); 04417 04418 surface_translate_drawable_coords(surface, context->win_handle, &local_rect); 04419 glPixelZoom(1.0f, -1.0f); 04420 } 04421 else 04422 { 04423 /* Primary offscreen render target */ 04424 TRACE("Offscreen render target.\n"); 04425 context_set_draw_buffer(context, device->offscreenBuffer); 04426 04427 glPixelZoom(1.0f, 1.0f); 04428 } 04429 04430 glRasterPos3i(local_rect.left, local_rect.top, 1); 04431 checkGLcall("glRasterPos3i"); 04432 04433 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */ 04434 glPixelStorei(GL_UNPACK_ROW_LENGTH, surface->resource.width); 04435 04436 if (surface->flags & SFLAG_PBO) 04437 { 04438 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo)); 04439 checkGLcall("glBindBufferARB"); 04440 } 04441 04442 glDrawPixels(w, h, fmt, type, mem); 04443 checkGLcall("glDrawPixels"); 04444 04445 if (surface->flags & SFLAG_PBO) 04446 { 04447 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0)); 04448 checkGLcall("glBindBufferARB"); 04449 } 04450 04451 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); 04452 checkGLcall("glPixelStorei(GL_UNPACK_ROW_LENGTH, 0)"); 04453 04454 LEAVE_GL(); 04455 04456 if (wined3d_settings.strict_draw_ordering 04457 || (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN 04458 && surface->container.u.swapchain->front_buffer == surface)) 04459 wglFlush(); 04460 04461 context_release(context); 04462 } 04463 04464 HRESULT d3dfmt_get_conv(const struct wined3d_surface *surface, BOOL need_alpha_ck, 04465 BOOL use_texturing, struct wined3d_format *format, CONVERT_TYPES *convert) 04466 { 04467 BOOL colorkey_active = need_alpha_ck && (surface->CKeyFlags & WINEDDSD_CKSRCBLT); 04468 const struct wined3d_device *device = surface->resource.device; 04469 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; 04470 BOOL blit_supported = FALSE; 04471 04472 /* Copy the default values from the surface. Below we might perform fixups */ 04473 /* TODO: get rid of color keying desc fixups by using e.g. a table. */ 04474 *format = *surface->resource.format; 04475 *convert = NO_CONVERSION; 04476 04477 /* Ok, now look if we have to do any conversion */ 04478 switch (surface->resource.format->id) 04479 { 04480 case WINED3DFMT_P8_UINT: 04481 /* Below the call to blit_supported is disabled for Wine 1.2 04482 * because the function isn't operating correctly yet. At the 04483 * moment 8-bit blits are handled in software and if certain GL 04484 * extensions are around, surface conversion is performed at 04485 * upload time. The blit_supported call recognizes it as a 04486 * destination fixup. This type of upload 'fixup' and 8-bit to 04487 * 8-bit blits need to be handled by the blit_shader. 04488 * TODO: get rid of this #if 0. */ 04489 #if 0 04490 blit_supported = device->blitter->blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_BLIT, 04491 &rect, surface->resource.usage, surface->resource.pool, surface->resource.format, 04492 &rect, surface->resource.usage, surface->resource.pool, surface->resource.format); 04493 #endif 04494 blit_supported = gl_info->supported[EXT_PALETTED_TEXTURE] || gl_info->supported[ARB_FRAGMENT_PROGRAM]; 04495 04496 /* Use conversion when the blit_shader backend supports it. It only supports this in case of 04497 * texturing. Further also use conversion in case of color keying. 04498 * Paletted textures can be emulated using shaders but only do that for 2D purposes e.g. situations 04499 * in which the main render target uses p8. Some games like GTA Vice City use P8 for texturing which 04500 * conflicts with this. 04501 */ 04502 if (!((blit_supported && device->fb.render_targets && surface == device->fb.render_targets[0])) 04503 || colorkey_active || !use_texturing) 04504 { 04505 format->glFormat = GL_RGBA; 04506 format->glInternal = GL_RGBA; 04507 format->glType = GL_UNSIGNED_BYTE; 04508 format->conv_byte_count = 4; 04509 if (colorkey_active) 04510 *convert = CONVERT_PALETTED_CK; 04511 else 04512 *convert = CONVERT_PALETTED; 04513 } 04514 break; 04515 04516 case WINED3DFMT_B2G3R3_UNORM: 04517 /* ********************** 04518 GL_UNSIGNED_BYTE_3_3_2 04519 ********************** */ 04520 if (colorkey_active) { 04521 /* This texture format will never be used.. So do not care about color keying 04522 up until the point in time it will be needed :-) */ 04523 FIXME(" ColorKeying not supported in the RGB 332 format !\n"); 04524 } 04525 break; 04526 04527 case WINED3DFMT_B5G6R5_UNORM: 04528 if (colorkey_active) 04529 { 04530 *convert = CONVERT_CK_565; 04531 format->glFormat = GL_RGBA; 04532 format->glInternal = GL_RGB5_A1; 04533 format->glType = GL_UNSIGNED_SHORT_5_5_5_1; 04534 format->conv_byte_count = 2; 04535 } 04536 break; 04537 04538 case WINED3DFMT_B5G5R5X1_UNORM: 04539 if (colorkey_active) 04540 { 04541 *convert = CONVERT_CK_5551; 04542 format->glFormat = GL_BGRA; 04543 format->glInternal = GL_RGB5_A1; 04544 format->glType = GL_UNSIGNED_SHORT_1_5_5_5_REV; 04545 format->conv_byte_count = 2; 04546 } 04547 break; 04548 04549 case WINED3DFMT_B8G8R8_UNORM: 04550 if (colorkey_active) 04551 { 04552 *convert = CONVERT_CK_RGB24; 04553 format->glFormat = GL_RGBA; 04554 format->glInternal = GL_RGBA8; 04555 format->glType = GL_UNSIGNED_INT_8_8_8_8; 04556 format->conv_byte_count = 4; 04557 } 04558 break; 04559 04560 case WINED3DFMT_B8G8R8X8_UNORM: 04561 if (colorkey_active) 04562 { 04563 *convert = CONVERT_RGB32_888; 04564 format->glFormat = GL_RGBA; 04565 format->glInternal = GL_RGBA8; 04566 format->glType = GL_UNSIGNED_INT_8_8_8_8; 04567 format->conv_byte_count = 4; 04568 } 04569 break; 04570 04571 default: 04572 break; 04573 } 04574 04575 if (*convert != NO_CONVERSION) 04576 { 04577 format->rtInternal = format->glInternal; 04578 format->glGammaInternal = format->glInternal; 04579 } 04580 04581 return WINED3D_OK; 04582 } 04583 04584 static BOOL color_in_range(const struct wined3d_color_key *color_key, DWORD color) 04585 { 04586 /* FIXME: Is this really how color keys are supposed to work? I think it 04587 * makes more sense to compare the individual channels. */ 04588 return color >= color_key->color_space_low_value 04589 && color <= color_key->color_space_high_value; 04590 } 04591 04592 void d3dfmt_p8_init_palette(const struct wined3d_surface *surface, BYTE table[256][4], BOOL colorkey) 04593 { 04594 const struct wined3d_device *device = surface->resource.device; 04595 const struct wined3d_palette *pal = surface->palette; 04596 BOOL index_in_alpha = FALSE; 04597 unsigned int i; 04598 04599 /* Old games like StarCraft, C&C, Red Alert and others use P8 render targets. 04600 * Reading back the RGB output each lockrect (each frame as they lock the whole screen) 04601 * is slow. Further RGB->P8 conversion is not possible because palettes can have 04602 * duplicate entries. Store the color key in the unused alpha component to speed the 04603 * download up and to make conversion unneeded. */ 04604 index_in_alpha = primary_render_target_is_p8(device); 04605 04606 if (!pal) 04607 { 04608 ERR("This code should never get entered for DirectDraw!, expect problems\n"); 04609 if (index_in_alpha) 04610 { 04611 /* Guarantees that memory representation remains correct after sysmem<->texture transfers even if 04612 * there's no palette at this time. */ 04613 for (i = 0; i < 256; i++) table[i][3] = i; 04614 } 04615 } 04616 else 04617 { 04618 TRACE("Using surface palette %p\n", pal); 04619 /* Get the surface's palette */ 04620 for (i = 0; i < 256; ++i) 04621 { 04622 table[i][0] = pal->palents[i].peRed; 04623 table[i][1] = pal->palents[i].peGreen; 04624 table[i][2] = pal->palents[i].peBlue; 04625 04626 /* When index_in_alpha is set the palette index is stored in the 04627 * alpha component. In case of a readback we can then read 04628 * GL_ALPHA. Color keying is handled in BltOverride using a 04629 * GL_ALPHA_TEST using GL_NOT_EQUAL. In case of index_in_alpha the 04630 * color key itself is passed to glAlphaFunc in other cases the 04631 * alpha component of pixels that should be masked away is set to 0. */ 04632 if (index_in_alpha) 04633 table[i][3] = i; 04634 else if (colorkey && color_in_range(&surface->src_blt_color_key, i)) 04635 table[i][3] = 0x00; 04636 else if (pal->flags & WINEDDPCAPS_ALPHA) 04637 table[i][3] = pal->palents[i].peFlags; 04638 else 04639 table[i][3] = 0xFF; 04640 } 04641 } 04642 } 04643 04644 static HRESULT d3dfmt_convert_surface(const BYTE *src, BYTE *dst, UINT pitch, UINT width, 04645 UINT height, UINT outpitch, CONVERT_TYPES convert, struct wined3d_surface *surface) 04646 { 04647 const BYTE *source; 04648 BYTE *dest; 04649 TRACE("(%p)->(%p),(%d,%d,%d,%d,%p)\n", src, dst, pitch, height, outpitch, convert, surface); 04650 04651 switch (convert) { 04652 case NO_CONVERSION: 04653 { 04654 memcpy(dst, src, pitch * height); 04655 break; 04656 } 04657 case CONVERT_PALETTED: 04658 case CONVERT_PALETTED_CK: 04659 { 04660 BYTE table[256][4]; 04661 unsigned int x, y; 04662 04663 d3dfmt_p8_init_palette(surface, table, (convert == CONVERT_PALETTED_CK)); 04664 04665 for (y = 0; y < height; y++) 04666 { 04667 source = src + pitch * y; 04668 dest = dst + outpitch * y; 04669 /* This is an 1 bpp format, using the width here is fine */ 04670 for (x = 0; x < width; x++) { 04671 BYTE color = *source++; 04672 *dest++ = table[color][0]; 04673 *dest++ = table[color][1]; 04674 *dest++ = table[color][2]; 04675 *dest++ = table[color][3]; 04676 } 04677 } 04678 } 04679 break; 04680 04681 case CONVERT_CK_565: 04682 { 04683 /* Converting the 565 format in 5551 packed to emulate color-keying. 04684 04685 Note : in all these conversion, it would be best to average the averaging 04686 pixels to get the color of the pixel that will be color-keyed to 04687 prevent 'color bleeding'. This will be done later on if ever it is 04688 too visible. 04689 04690 Note2: Nvidia documents say that their driver does not support alpha + color keying 04691 on the same surface and disables color keying in such a case 04692 */ 04693 unsigned int x, y; 04694 const WORD *Source; 04695 WORD *Dest; 04696 04697 TRACE("Color keyed 565\n"); 04698 04699 for (y = 0; y < height; y++) { 04700 Source = (const WORD *)(src + y * pitch); 04701 Dest = (WORD *) (dst + y * outpitch); 04702 for (x = 0; x < width; x++ ) { 04703 WORD color = *Source++; 04704 *Dest = ((color & 0xFFC0) | ((color & 0x1F) << 1)); 04705 if (!color_in_range(&surface->src_blt_color_key, color)) 04706 *Dest |= 0x0001; 04707 Dest++; 04708 } 04709 } 04710 } 04711 break; 04712 04713 case CONVERT_CK_5551: 04714 { 04715 /* Converting X1R5G5B5 format to R5G5B5A1 to emulate color-keying. */ 04716 unsigned int x, y; 04717 const WORD *Source; 04718 WORD *Dest; 04719 TRACE("Color keyed 5551\n"); 04720 for (y = 0; y < height; y++) { 04721 Source = (const WORD *)(src + y * pitch); 04722 Dest = (WORD *) (dst + y * outpitch); 04723 for (x = 0; x < width; x++ ) { 04724 WORD color = *Source++; 04725 *Dest = color; 04726 if (!color_in_range(&surface->src_blt_color_key, color)) 04727 *Dest |= (1 << 15); 04728 else 04729 *Dest &= ~(1 << 15); 04730 Dest++; 04731 } 04732 } 04733 } 04734 break; 04735 04736 case CONVERT_CK_RGB24: 04737 { 04738 /* Converting R8G8B8 format to R8G8B8A8 with color-keying. */ 04739 unsigned int x, y; 04740 for (y = 0; y < height; y++) 04741 { 04742 source = src + pitch * y; 04743 dest = dst + outpitch * y; 04744 for (x = 0; x < width; x++) { 04745 DWORD color = ((DWORD)source[0] << 16) + ((DWORD)source[1] << 8) + (DWORD)source[2] ; 04746 DWORD dstcolor = color << 8; 04747 if (!color_in_range(&surface->src_blt_color_key, color)) 04748 dstcolor |= 0xff; 04749 *(DWORD*)dest = dstcolor; 04750 source += 3; 04751 dest += 4; 04752 } 04753 } 04754 } 04755 break; 04756 04757 case CONVERT_RGB32_888: 04758 { 04759 /* Converting X8R8G8B8 format to R8G8B8A8 with color-keying. */ 04760 unsigned int x, y; 04761 for (y = 0; y < height; y++) 04762 { 04763 source = src + pitch * y; 04764 dest = dst + outpitch * y; 04765 for (x = 0; x < width; x++) { 04766 DWORD color = 0xffffff & *(const DWORD*)source; 04767 DWORD dstcolor = color << 8; 04768 if (!color_in_range(&surface->src_blt_color_key, color)) 04769 dstcolor |= 0xff; 04770 *(DWORD*)dest = dstcolor; 04771 source += 4; 04772 dest += 4; 04773 } 04774 } 04775 } 04776 break; 04777 04778 default: 04779 ERR("Unsupported conversion type %#x.\n", convert); 04780 } 04781 return WINED3D_OK; 04782 } 04783 04784 void flip_surface(struct wined3d_surface *front, struct wined3d_surface *back) 04785 { 04786 /* Flip the surface contents */ 04787 /* Flip the DC */ 04788 { 04789 HDC tmp; 04790 tmp = front->hDC; 04791 front->hDC = back->hDC; 04792 back->hDC = tmp; 04793 } 04794 04795 /* Flip the DIBsection */ 04796 { 04797 HBITMAP tmp = front->dib.DIBsection; 04798 front->dib.DIBsection = back->dib.DIBsection; 04799 back->dib.DIBsection = tmp; 04800 } 04801 04802 /* Flip the surface data */ 04803 { 04804 void* tmp; 04805 04806 tmp = front->dib.bitmap_data; 04807 front->dib.bitmap_data = back->dib.bitmap_data; 04808 back->dib.bitmap_data = tmp; 04809 04810 tmp = front->resource.allocatedMemory; 04811 front->resource.allocatedMemory = back->resource.allocatedMemory; 04812 back->resource.allocatedMemory = tmp; 04813 04814 tmp = front->resource.heapMemory; 04815 front->resource.heapMemory = back->resource.heapMemory; 04816 back->resource.heapMemory = tmp; 04817 } 04818 04819 /* Flip the PBO */ 04820 { 04821 GLuint tmp_pbo = front->pbo; 04822 front->pbo = back->pbo; 04823 back->pbo = tmp_pbo; 04824 } 04825 04826 /* Flip the opengl texture */ 04827 { 04828 GLuint tmp; 04829 04830 tmp = back->texture_name; 04831 back->texture_name = front->texture_name; 04832 front->texture_name = tmp; 04833 04834 tmp = back->texture_name_srgb; 04835 back->texture_name_srgb = front->texture_name_srgb; 04836 front->texture_name_srgb = tmp; 04837 04838 tmp = back->rb_multisample; 04839 back->rb_multisample = front->rb_multisample; 04840 front->rb_multisample = tmp; 04841 04842 tmp = back->rb_resolved; 04843 back->rb_resolved = front->rb_resolved; 04844 front->rb_resolved = tmp; 04845 04846 resource_unload(&back->resource); 04847 resource_unload(&front->resource); 04848 } 04849 04850 { 04851 DWORD tmp_flags = back->flags; 04852 back->flags = front->flags; 04853 front->flags = tmp_flags; 04854 } 04855 } 04856 04857 /* Does a direct frame buffer -> texture copy. Stretching is done with single 04858 * pixel copy calls. */ 04859 static void fb_copy_to_texture_direct(struct wined3d_surface *dst_surface, struct wined3d_surface *src_surface, 04860 const RECT *src_rect, const RECT *dst_rect_in, enum wined3d_texture_filter_type filter) 04861 { 04862 struct wined3d_device *device = dst_surface->resource.device; 04863 float xrel, yrel; 04864 UINT row; 04865 struct wined3d_context *context; 04866 BOOL upsidedown = FALSE; 04867 RECT dst_rect = *dst_rect_in; 04868 04869 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag 04870 * glCopyTexSubImage is a bit picky about the parameters we pass to it 04871 */ 04872 if(dst_rect.top > dst_rect.bottom) { 04873 UINT tmp = dst_rect.bottom; 04874 dst_rect.bottom = dst_rect.top; 04875 dst_rect.top = tmp; 04876 upsidedown = TRUE; 04877 } 04878 04879 context = context_acquire(device, src_surface); 04880 context_apply_blit_state(context, device); 04881 surface_internal_preload(dst_surface, SRGB_RGB); 04882 ENTER_GL(); 04883 04884 /* Bind the target texture */ 04885 context_bind_texture(context, dst_surface->texture_target, dst_surface->texture_name); 04886 if (surface_is_offscreen(src_surface)) 04887 { 04888 TRACE("Reading from an offscreen target\n"); 04889 upsidedown = !upsidedown; 04890 glReadBuffer(device->offscreenBuffer); 04891 } 04892 else 04893 { 04894 glReadBuffer(surface_get_gl_buffer(src_surface)); 04895 } 04896 checkGLcall("glReadBuffer"); 04897 04898 xrel = (float) (src_rect->right - src_rect->left) / (float) (dst_rect.right - dst_rect.left); 04899 yrel = (float) (src_rect->bottom - src_rect->top) / (float) (dst_rect.bottom - dst_rect.top); 04900 04901 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps)) 04902 { 04903 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n"); 04904 04905 if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT) 04906 ERR("Texture filtering not supported in direct blit.\n"); 04907 } 04908 else if ((filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT) 04909 && ((yrel - 1.0f < -eps) || (yrel - 1.0f > eps))) 04910 { 04911 ERR("Texture filtering not supported in direct blit\n"); 04912 } 04913 04914 if (upsidedown 04915 && !((xrel - 1.0f < -eps) || (xrel - 1.0f > eps)) 04916 && !((yrel - 1.0f < -eps) || (yrel - 1.0f > eps))) 04917 { 04918 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do */ 04919 04920 glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level, 04921 dst_rect.left /*xoffset */, dst_rect.top /* y offset */, 04922 src_rect->left, src_surface->resource.height - src_rect->bottom, 04923 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top); 04924 } 04925 else 04926 { 04927 UINT yoffset = src_surface->resource.height - src_rect->top + dst_rect.top - 1; 04928 /* I have to process this row by row to swap the image, 04929 * otherwise it would be upside down, so stretching in y direction 04930 * doesn't cost extra time 04931 * 04932 * However, stretching in x direction can be avoided if not necessary 04933 */ 04934 for(row = dst_rect.top; row < dst_rect.bottom; row++) { 04935 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps)) 04936 { 04937 /* Well, that stuff works, but it's very slow. 04938 * find a better way instead 04939 */ 04940 UINT col; 04941 04942 for (col = dst_rect.left; col < dst_rect.right; ++col) 04943 { 04944 glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level, 04945 dst_rect.left + col /* x offset */, row /* y offset */, 04946 src_rect->left + col * xrel, yoffset - (int) (row * yrel), 1, 1); 04947 } 04948 } 04949 else 04950 { 04951 glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level, 04952 dst_rect.left /* x offset */, row /* y offset */, 04953 src_rect->left, yoffset - (int) (row * yrel), dst_rect.right - dst_rect.left, 1); 04954 } 04955 } 04956 } 04957 checkGLcall("glCopyTexSubImage2D"); 04958 04959 LEAVE_GL(); 04960 context_release(context); 04961 04962 /* The texture is now most up to date - If the surface is a render target and has a drawable, this 04963 * path is never entered 04964 */ 04965 surface_modify_location(dst_surface, SFLAG_INTEXTURE, TRUE); 04966 } 04967 04968 /* Uses the hardware to stretch and flip the image */ 04969 static void fb_copy_to_texture_hwstretch(struct wined3d_surface *dst_surface, struct wined3d_surface *src_surface, 04970 const RECT *src_rect, const RECT *dst_rect_in, enum wined3d_texture_filter_type filter) 04971 { 04972 struct wined3d_device *device = dst_surface->resource.device; 04973 struct wined3d_swapchain *src_swapchain = NULL; 04974 GLuint src, backup = 0; 04975 float left, right, top, bottom; /* Texture coordinates */ 04976 UINT fbwidth = src_surface->resource.width; 04977 UINT fbheight = src_surface->resource.height; 04978 struct wined3d_context *context; 04979 GLenum drawBuffer = GL_BACK; 04980 GLenum texture_target; 04981 BOOL noBackBufferBackup; 04982 BOOL src_offscreen; 04983 BOOL upsidedown = FALSE; 04984 RECT dst_rect = *dst_rect_in; 04985 04986 TRACE("Using hwstretch blit\n"); 04987 /* Activate the Proper context for reading from the source surface, set it up for blitting */ 04988 context = context_acquire(device, src_surface); 04989 context_apply_blit_state(context, device); 04990 surface_internal_preload(dst_surface, SRGB_RGB); 04991 04992 src_offscreen = surface_is_offscreen(src_surface); 04993 noBackBufferBackup = src_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO; 04994 if (!noBackBufferBackup && !src_surface->texture_name) 04995 { 04996 /* Get it a description */ 04997 surface_internal_preload(src_surface, SRGB_RGB); 04998 } 04999 ENTER_GL(); 05000 05001 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring. 05002 * This way we don't have to wait for the 2nd readback to finish to leave this function. 05003 */ 05004 if (context->aux_buffers >= 2) 05005 { 05006 /* Got more than one aux buffer? Use the 2nd aux buffer */ 05007 drawBuffer = GL_AUX1; 05008 } 05009 else if ((!src_offscreen || device->offscreenBuffer == GL_BACK) && context->aux_buffers >= 1) 05010 { 05011 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */ 05012 drawBuffer = GL_AUX0; 05013 } 05014 05015 if(noBackBufferBackup) { 05016 glGenTextures(1, &backup); 05017 checkGLcall("glGenTextures"); 05018 context_bind_texture(context, GL_TEXTURE_2D, backup); 05019 texture_target = GL_TEXTURE_2D; 05020 } else { 05021 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If 05022 * we are reading from the back buffer, the backup can be used as source texture 05023 */ 05024 texture_target = src_surface->texture_target; 05025 context_bind_texture(context, texture_target, src_surface->texture_name); 05026 glEnable(texture_target); 05027 checkGLcall("glEnable(texture_target)"); 05028 05029 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */ 05030 src_surface->flags &= ~SFLAG_INTEXTURE; 05031 } 05032 05033 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag 05034 * glCopyTexSubImage is a bit picky about the parameters we pass to it 05035 */ 05036 if(dst_rect.top > dst_rect.bottom) { 05037 UINT tmp = dst_rect.bottom; 05038 dst_rect.bottom = dst_rect.top; 05039 dst_rect.top = tmp; 05040 upsidedown = TRUE; 05041 } 05042 05043 if (src_offscreen) 05044 { 05045 TRACE("Reading from an offscreen target\n"); 05046 upsidedown = !upsidedown; 05047 glReadBuffer(device->offscreenBuffer); 05048 } 05049 else 05050 { 05051 glReadBuffer(surface_get_gl_buffer(src_surface)); 05052 } 05053 05054 /* TODO: Only back up the part that will be overwritten */ 05055 glCopyTexSubImage2D(texture_target, 0, 05056 0, 0 /* read offsets */, 05057 0, 0, 05058 fbwidth, 05059 fbheight); 05060 05061 checkGLcall("glCopyTexSubImage2D"); 05062 05063 /* No issue with overriding these - the sampler is dirty due to blit usage */ 05064 glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, 05065 wined3d_gl_mag_filter(magLookup, filter)); 05066 checkGLcall("glTexParameteri"); 05067 glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, 05068 wined3d_gl_min_mip_filter(minMipLookup, filter, WINED3D_TEXF_NONE)); 05069 checkGLcall("glTexParameteri"); 05070 05071 if (src_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN) 05072 src_swapchain = src_surface->container.u.swapchain; 05073 if (!src_swapchain || src_surface == src_swapchain->back_buffers[0]) 05074 { 05075 src = backup ? backup : src_surface->texture_name; 05076 } 05077 else 05078 { 05079 glReadBuffer(GL_FRONT); 05080 checkGLcall("glReadBuffer(GL_FRONT)"); 05081 05082 glGenTextures(1, &src); 05083 checkGLcall("glGenTextures(1, &src)"); 05084 context_bind_texture(context, GL_TEXTURE_2D, src); 05085 05086 /* TODO: Only copy the part that will be read. Use src_rect->left, src_rect->bottom as origin, but with the width watch 05087 * out for power of 2 sizes 05088 */ 05089 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, src_surface->pow2Width, 05090 src_surface->pow2Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); 05091 checkGLcall("glTexImage2D"); 05092 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 05093 0, 0 /* read offsets */, 05094 0, 0, 05095 fbwidth, 05096 fbheight); 05097 05098 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 05099 checkGLcall("glTexParameteri"); 05100 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 05101 checkGLcall("glTexParameteri"); 05102 05103 glReadBuffer(GL_BACK); 05104 checkGLcall("glReadBuffer(GL_BACK)"); 05105 05106 if(texture_target != GL_TEXTURE_2D) { 05107 glDisable(texture_target); 05108 glEnable(GL_TEXTURE_2D); 05109 texture_target = GL_TEXTURE_2D; 05110 } 05111 } 05112 checkGLcall("glEnd and previous"); 05113 05114 left = src_rect->left; 05115 right = src_rect->right; 05116 05117 if (!upsidedown) 05118 { 05119 top = src_surface->resource.height - src_rect->top; 05120 bottom = src_surface->resource.height - src_rect->bottom; 05121 } 05122 else 05123 { 05124 top = src_surface->resource.height - src_rect->bottom; 05125 bottom = src_surface->resource.height - src_rect->top; 05126 } 05127 05128 if (src_surface->flags & SFLAG_NORMCOORD) 05129 { 05130 left /= src_surface->pow2Width; 05131 right /= src_surface->pow2Width; 05132 top /= src_surface->pow2Height; 05133 bottom /= src_surface->pow2Height; 05134 } 05135 05136 /* draw the source texture stretched and upside down. The correct surface is bound already */ 05137 glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP); 05138 glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP); 05139 05140 context_set_draw_buffer(context, drawBuffer); 05141 glReadBuffer(drawBuffer); 05142 05143 glBegin(GL_QUADS); 05144 /* bottom left */ 05145 glTexCoord2f(left, bottom); 05146 glVertex2i(0, 0); 05147 05148 /* top left */ 05149 glTexCoord2f(left, top); 05150 glVertex2i(0, dst_rect.bottom - dst_rect.top); 05151 05152 /* top right */ 05153 glTexCoord2f(right, top); 05154 glVertex2i(dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top); 05155 05156 /* bottom right */ 05157 glTexCoord2f(right, bottom); 05158 glVertex2i(dst_rect.right - dst_rect.left, 0); 05159 glEnd(); 05160 checkGLcall("glEnd and previous"); 05161 05162 if (texture_target != dst_surface->texture_target) 05163 { 05164 glDisable(texture_target); 05165 glEnable(dst_surface->texture_target); 05166 texture_target = dst_surface->texture_target; 05167 } 05168 05169 /* Now read the stretched and upside down image into the destination texture */ 05170 context_bind_texture(context, texture_target, dst_surface->texture_name); 05171 glCopyTexSubImage2D(texture_target, 05172 0, 05173 dst_rect.left, dst_rect.top, /* xoffset, yoffset */ 05174 0, 0, /* We blitted the image to the origin */ 05175 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top); 05176 checkGLcall("glCopyTexSubImage2D"); 05177 05178 if(drawBuffer == GL_BACK) { 05179 /* Write the back buffer backup back */ 05180 if(backup) { 05181 if(texture_target != GL_TEXTURE_2D) { 05182 glDisable(texture_target); 05183 glEnable(GL_TEXTURE_2D); 05184 texture_target = GL_TEXTURE_2D; 05185 } 05186 context_bind_texture(context, GL_TEXTURE_2D, backup); 05187 } 05188 else 05189 { 05190 if (texture_target != src_surface->texture_target) 05191 { 05192 glDisable(texture_target); 05193 glEnable(src_surface->texture_target); 05194 texture_target = src_surface->texture_target; 05195 } 05196 context_bind_texture(context, src_surface->texture_target, src_surface->texture_name); 05197 } 05198 05199 glBegin(GL_QUADS); 05200 /* top left */ 05201 glTexCoord2f(0.0f, 0.0f); 05202 glVertex2i(0, fbheight); 05203 05204 /* bottom left */ 05205 glTexCoord2f(0.0f, (float)fbheight / (float)src_surface->pow2Height); 05206 glVertex2i(0, 0); 05207 05208 /* bottom right */ 05209 glTexCoord2f((float)fbwidth / (float)src_surface->pow2Width, 05210 (float)fbheight / (float)src_surface->pow2Height); 05211 glVertex2i(fbwidth, 0); 05212 05213 /* top right */ 05214 glTexCoord2f((float)fbwidth / (float)src_surface->pow2Width, 0.0f); 05215 glVertex2i(fbwidth, fbheight); 05216 glEnd(); 05217 } 05218 glDisable(texture_target); 05219 checkGLcall("glDisable(texture_target)"); 05220 05221 /* Cleanup */ 05222 if (src != src_surface->texture_name && src != backup) 05223 { 05224 glDeleteTextures(1, &src); 05225 checkGLcall("glDeleteTextures(1, &src)"); 05226 } 05227 if(backup) { 05228 glDeleteTextures(1, &backup); 05229 checkGLcall("glDeleteTextures(1, &backup)"); 05230 } 05231 05232 LEAVE_GL(); 05233 05234 if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */ 05235 05236 context_release(context); 05237 05238 /* The texture is now most up to date - If the surface is a render target and has a drawable, this 05239 * path is never entered 05240 */ 05241 surface_modify_location(dst_surface, SFLAG_INTEXTURE, TRUE); 05242 } 05243 05244 /* Front buffer coordinates are always full screen coordinates, but our GL 05245 * drawable is limited to the window's client area. The sysmem and texture 05246 * copies do have the full screen size. Note that GL has a bottom-left 05247 * origin, while D3D has a top-left origin. */ 05248 void surface_translate_drawable_coords(const struct wined3d_surface *surface, HWND window, RECT *rect) 05249 { 05250 UINT drawable_height; 05251 05252 if (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN 05253 && surface == surface->container.u.swapchain->front_buffer) 05254 { 05255 POINT offset = {0, 0}; 05256 RECT windowsize; 05257 05258 ScreenToClient(window, &offset); 05259 OffsetRect(rect, offset.x, offset.y); 05260 05261 GetClientRect(window, &windowsize); 05262 drawable_height = windowsize.bottom - windowsize.top; 05263 } 05264 else 05265 { 05266 drawable_height = surface->resource.height; 05267 } 05268 05269 rect->top = drawable_height - rect->top; 05270 rect->bottom = drawable_height - rect->bottom; 05271 } 05272 05273 static void surface_blt_to_drawable(const struct wined3d_device *device, 05274 enum wined3d_texture_filter_type filter, BOOL color_key, 05275 struct wined3d_surface *src_surface, const RECT *src_rect_in, 05276 struct wined3d_surface *dst_surface, const RECT *dst_rect_in) 05277 { 05278 struct wined3d_context *context; 05279 RECT src_rect, dst_rect; 05280 05281 src_rect = *src_rect_in; 05282 dst_rect = *dst_rect_in; 05283 05284 /* Make sure the surface is up-to-date. This should probably use 05285 * surface_load_location() and worry about the destination surface too, 05286 * unless we're overwriting it completely. */ 05287 surface_internal_preload(src_surface, SRGB_RGB); 05288 05289 /* Activate the destination context, set it up for blitting */ 05290 context = context_acquire(device, dst_surface); 05291 context_apply_blit_state(context, device); 05292 05293 if (!surface_is_offscreen(dst_surface)) 05294 surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect); 05295 05296 device->blitter->set_shader(device->blit_priv, context, src_surface); 05297 05298 ENTER_GL(); 05299 05300 if (color_key) 05301 { 05302 glEnable(GL_ALPHA_TEST); 05303 checkGLcall("glEnable(GL_ALPHA_TEST)"); 05304 05305 /* When the primary render target uses P8, the alpha component 05306 * contains the palette index. Which means that the colorkey is one of 05307 * the palette entries. In other cases pixels that should be masked 05308 * away have alpha set to 0. */ 05309 if (primary_render_target_is_p8(device)) 05310 glAlphaFunc(GL_NOTEQUAL, (float)src_surface->src_blt_color_key.color_space_low_value / 256.0f); 05311 else 05312 glAlphaFunc(GL_NOTEQUAL, 0.0f); 05313 checkGLcall("glAlphaFunc"); 05314 } 05315 else 05316 { 05317 glDisable(GL_ALPHA_TEST); 05318 checkGLcall("glDisable(GL_ALPHA_TEST)"); 05319 } 05320 05321 draw_textured_quad(src_surface, context, &src_rect, &dst_rect, filter); 05322 05323 if (color_key) 05324 { 05325 glDisable(GL_ALPHA_TEST); 05326 checkGLcall("glDisable(GL_ALPHA_TEST)"); 05327 } 05328 05329 LEAVE_GL(); 05330 05331 /* Leave the opengl state valid for blitting */ 05332 device->blitter->unset_shader(context->gl_info); 05333 05334 if (wined3d_settings.strict_draw_ordering 05335 || (dst_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN 05336 && (dst_surface->container.u.swapchain->front_buffer == dst_surface))) 05337 wglFlush(); /* Flush to ensure ordering across contexts. */ 05338 05339 context_release(context); 05340 } 05341 05342 /* Do not call while under the GL lock. */ 05343 HRESULT surface_color_fill(struct wined3d_surface *s, const RECT *rect, const struct wined3d_color *color) 05344 { 05345 struct wined3d_device *device = s->resource.device; 05346 const struct blit_shader *blitter; 05347 05348 blitter = wined3d_select_blitter(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_FILL, 05349 NULL, 0, 0, NULL, rect, s->resource.usage, s->resource.pool, s->resource.format); 05350 if (!blitter) 05351 { 05352 FIXME("No blitter is capable of performing the requested color fill operation.\n"); 05353 return WINED3DERR_INVALIDCALL; 05354 } 05355 05356 return blitter->color_fill(device, s, rect, color); 05357 } 05358 05359 /* Do not call while under the GL lock. */ 05360 static HRESULT IWineD3DSurfaceImpl_BltOverride(struct wined3d_surface *dst_surface, const RECT *dst_rect, 05361 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags, const WINEDDBLTFX *DDBltFx, 05362 enum wined3d_texture_filter_type filter) 05363 { 05364 struct wined3d_device *device = dst_surface->resource.device; 05365 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; 05366 struct wined3d_swapchain *srcSwapchain = NULL, *dstSwapchain = NULL; 05367 05368 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, blt_fx %p, filter %s.\n", 05369 dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect), 05370 flags, DDBltFx, debug_d3dtexturefiltertype(filter)); 05371 05372 /* Get the swapchain. One of the surfaces has to be a primary surface */ 05373 if (dst_surface->resource.pool == WINED3D_POOL_SYSTEM_MEM) 05374 { 05375 WARN("Destination is in sysmem, rejecting gl blt\n"); 05376 return WINED3DERR_INVALIDCALL; 05377 } 05378 05379 if (dst_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN) 05380 dstSwapchain = dst_surface->container.u.swapchain; 05381 05382 if (src_surface) 05383 { 05384 if (src_surface->resource.pool == WINED3D_POOL_SYSTEM_MEM) 05385 { 05386 WARN("Src is in sysmem, rejecting gl blt\n"); 05387 return WINED3DERR_INVALIDCALL; 05388 } 05389 05390 if (src_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN) 05391 srcSwapchain = src_surface->container.u.swapchain; 05392 } 05393 05394 /* Early sort out of cases where no render target is used */ 05395 if (!dstSwapchain && !srcSwapchain 05396 && src_surface != device->fb.render_targets[0] 05397 && dst_surface != device->fb.render_targets[0]) 05398 { 05399 TRACE("No surface is render target, not using hardware blit.\n"); 05400 return WINED3DERR_INVALIDCALL; 05401 } 05402 05403 /* No destination color keying supported */ 05404 if (flags & (WINEDDBLT_KEYDEST | WINEDDBLT_KEYDESTOVERRIDE)) 05405 { 05406 /* Can we support that with glBlendFunc if blitting to the frame buffer? */ 05407 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n"); 05408 return WINED3DERR_INVALIDCALL; 05409 } 05410 05411 if (dstSwapchain && dstSwapchain == srcSwapchain) 05412 { 05413 FIXME("Implement hardware blit between two surfaces on the same swapchain\n"); 05414 return WINED3DERR_INVALIDCALL; 05415 } 05416 05417 if (dstSwapchain && srcSwapchain) 05418 { 05419 FIXME("Implement hardware blit between two different swapchains\n"); 05420 return WINED3DERR_INVALIDCALL; 05421 } 05422 05423 if (dstSwapchain) 05424 { 05425 /* Handled with regular texture -> swapchain blit */ 05426 if (src_surface == device->fb.render_targets[0]) 05427 TRACE("Blit from active render target to a swapchain\n"); 05428 } 05429 else if (srcSwapchain && dst_surface == device->fb.render_targets[0]) 05430 { 05431 FIXME("Implement blit from a swapchain to the active render target\n"); 05432 return WINED3DERR_INVALIDCALL; 05433 } 05434 05435 if ((srcSwapchain || src_surface == device->fb.render_targets[0]) && !dstSwapchain) 05436 { 05437 /* Blit from render target to texture */ 05438 BOOL stretchx; 05439 05440 /* P8 read back is not implemented */ 05441 if (src_surface->resource.format->id == WINED3DFMT_P8_UINT 05442 || dst_surface->resource.format->id == WINED3DFMT_P8_UINT) 05443 { 05444 TRACE("P8 read back not supported by frame buffer to texture blit\n"); 05445 return WINED3DERR_INVALIDCALL; 05446 } 05447 05448 if (flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE)) 05449 { 05450 TRACE("Color keying not supported by frame buffer to texture blit\n"); 05451 return WINED3DERR_INVALIDCALL; 05452 /* Destination color key is checked above */ 05453 } 05454 05455 if (dst_rect->right - dst_rect->left != src_rect->right - src_rect->left) 05456 stretchx = TRUE; 05457 else 05458 stretchx = FALSE; 05459 05460 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot 05461 * flip the image nor scale it. 05462 * 05463 * -> If the app asks for a unscaled, upside down copy, just perform one glCopyTexSubImage2D call 05464 * -> If the app wants a image width an unscaled width, copy it line per line 05465 * -> If the app wants a image that is scaled on the x axis, and the destination rectangle is smaller 05466 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the 05467 * back buffer. This is slower than reading line per line, thus not used for flipping 05468 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied 05469 * pixel by pixel. */ 05470 if (!stretchx || dst_rect->right - dst_rect->left > src_surface->resource.width 05471 || dst_rect->bottom - dst_rect->top > src_surface->resource.height) 05472 { 05473 TRACE("No stretching in x direction, using direct framebuffer -> texture copy.\n"); 05474 fb_copy_to_texture_direct(dst_surface, src_surface, src_rect, dst_rect, filter); 05475 } 05476 else 05477 { 05478 TRACE("Using hardware stretching to flip / stretch the texture.\n"); 05479 fb_copy_to_texture_hwstretch(dst_surface, src_surface, src_rect, dst_rect, filter); 05480 } 05481 05482 if (!(dst_surface->flags & SFLAG_DONOTFREE)) 05483 { 05484 HeapFree(GetProcessHeap(), 0, dst_surface->resource.heapMemory); 05485 dst_surface->resource.allocatedMemory = NULL; 05486 dst_surface->resource.heapMemory = NULL; 05487 } 05488 else 05489 { 05490 dst_surface->flags &= ~SFLAG_INSYSMEM; 05491 } 05492 05493 return WINED3D_OK; 05494 } 05495 else if (src_surface) 05496 { 05497 /* Blit from offscreen surface to render target */ 05498 struct wined3d_color_key old_blt_key = src_surface->src_blt_color_key; 05499 DWORD oldCKeyFlags = src_surface->CKeyFlags; 05500 05501 TRACE("Blt from surface %p to rendertarget %p\n", src_surface, dst_surface); 05502 05503 if (!device->blitter->blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT, 05504 src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format, 05505 dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format)) 05506 { 05507 FIXME("Unsupported blit operation falling back to software\n"); 05508 return WINED3DERR_INVALIDCALL; 05509 } 05510 05511 /* Color keying: Check if we have to do a color keyed blt, 05512 * and if not check if a color key is activated. 05513 * 05514 * Just modify the color keying parameters in the surface and restore them afterwards 05515 * The surface keeps track of the color key last used to load the opengl surface. 05516 * PreLoad will catch the change to the flags and color key and reload if necessary. 05517 */ 05518 if (flags & WINEDDBLT_KEYSRC) 05519 { 05520 /* Use color key from surface */ 05521 } 05522 else if (flags & WINEDDBLT_KEYSRCOVERRIDE) 05523 { 05524 /* Use color key from DDBltFx */ 05525 src_surface->CKeyFlags |= WINEDDSD_CKSRCBLT; 05526 src_surface->src_blt_color_key = DDBltFx->ddckSrcColorkey; 05527 } 05528 else 05529 { 05530 /* Do not use color key */ 05531 src_surface->CKeyFlags &= ~WINEDDSD_CKSRCBLT; 05532 } 05533 05534 surface_blt_to_drawable(device, filter, flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE), 05535 src_surface, src_rect, dst_surface, dst_rect); 05536 05537 /* Restore the color key parameters */ 05538 src_surface->CKeyFlags = oldCKeyFlags; 05539 src_surface->src_blt_color_key = old_blt_key; 05540 05541 surface_modify_location(dst_surface, dst_surface->draw_binding, TRUE); 05542 05543 return WINED3D_OK; 05544 } 05545 05546 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */ 05547 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n"); 05548 return WINED3DERR_INVALIDCALL; 05549 } 05550 05551 /* GL locking is done by the caller */ 05552 static void surface_depth_blt(const struct wined3d_surface *surface, struct wined3d_context *context, 05553 GLuint texture, GLint x, GLint y, GLsizei w, GLsizei h, GLenum target) 05554 { 05555 struct wined3d_device *device = surface->resource.device; 05556 const struct wined3d_gl_info *gl_info = context->gl_info; 05557 GLint compare_mode = GL_NONE; 05558 struct blt_info info; 05559 GLint old_binding = 0; 05560 RECT rect; 05561 05562 glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_VIEWPORT_BIT); 05563 05564 glDisable(GL_CULL_FACE); 05565 glDisable(GL_BLEND); 05566 glDisable(GL_ALPHA_TEST); 05567 glDisable(GL_SCISSOR_TEST); 05568 glDisable(GL_STENCIL_TEST); 05569 glEnable(GL_DEPTH_TEST); 05570 glDepthFunc(GL_ALWAYS); 05571 glDepthMask(GL_TRUE); 05572 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); 05573 glViewport(x, y, w, h); 05574 05575 SetRect(&rect, 0, h, w, 0); 05576 surface_get_blt_info(target, &rect, surface->pow2Width, surface->pow2Height, &info); 05577 context_active_texture(context, context->gl_info, 0); 05578 glGetIntegerv(info.binding, &old_binding); 05579 glBindTexture(info.bind_target, texture); 05580 if (gl_info->supported[ARB_SHADOW]) 05581 { 05582 glGetTexParameteriv(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, &compare_mode); 05583 if (compare_mode != GL_NONE) glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE); 05584 } 05585 05586 device->shader_backend->shader_select_depth_blt(device->shader_priv, 05587 gl_info, info.tex_type, &surface->ds_current_size); 05588 05589 glBegin(GL_TRIANGLE_STRIP); 05590 glTexCoord3fv(info.coords[0]); 05591 glVertex2f(-1.0f, -1.0f); 05592 glTexCoord3fv(info.coords[1]); 05593 glVertex2f(1.0f, -1.0f); 05594 glTexCoord3fv(info.coords[2]); 05595 glVertex2f(-1.0f, 1.0f); 05596 glTexCoord3fv(info.coords[3]); 05597 glVertex2f(1.0f, 1.0f); 05598 glEnd(); 05599 05600 if (compare_mode != GL_NONE) glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, compare_mode); 05601 glBindTexture(info.bind_target, old_binding); 05602 05603 glPopAttrib(); 05604 05605 device->shader_backend->shader_deselect_depth_blt(device->shader_priv, gl_info); 05606 } 05607 05608 void surface_modify_ds_location(struct wined3d_surface *surface, 05609 DWORD location, UINT w, UINT h) 05610 { 05611 TRACE("surface %p, new location %#x, w %u, h %u.\n", surface, location, w, h); 05612 05613 if (location & ~(SFLAG_LOCATIONS | SFLAG_LOST)) 05614 FIXME("Invalid location (%#x) specified.\n", location); 05615 05616 if (((surface->flags & SFLAG_INTEXTURE) && !(location & SFLAG_INTEXTURE)) 05617 || (!(surface->flags & SFLAG_INTEXTURE) && (location & SFLAG_INTEXTURE))) 05618 { 05619 if (surface->container.type == WINED3D_CONTAINER_TEXTURE) 05620 { 05621 TRACE("Passing to container.\n"); 05622 wined3d_texture_set_dirty(surface->container.u.texture, TRUE); 05623 } 05624 } 05625 05626 surface->ds_current_size.cx = w; 05627 surface->ds_current_size.cy = h; 05628 surface->flags &= ~(SFLAG_LOCATIONS | SFLAG_LOST); 05629 surface->flags |= location; 05630 } 05631 05632 /* Context activation is done by the caller. */ 05633 void surface_load_ds_location(struct wined3d_surface *surface, struct wined3d_context *context, DWORD location) 05634 { 05635 struct wined3d_device *device = surface->resource.device; 05636 GLsizei w, h; 05637 05638 TRACE("surface %p, new location %#x.\n", surface, location); 05639 05640 /* TODO: Make this work for modes other than FBO */ 05641 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return; 05642 05643 if (!(surface->flags & location)) 05644 { 05645 w = surface->ds_current_size.cx; 05646 h = surface->ds_current_size.cy; 05647 surface->ds_current_size.cx = 0; 05648 surface->ds_current_size.cy = 0; 05649 } 05650 else 05651 { 05652 w = surface->resource.width; 05653 h = surface->resource.height; 05654 } 05655 05656 if (surface->ds_current_size.cx == surface->resource.width 05657 && surface->ds_current_size.cy == surface->resource.height) 05658 { 05659 TRACE("Location (%#x) is already up to date.\n", location); 05660 return; 05661 } 05662 05663 if (surface->current_renderbuffer) 05664 { 05665 FIXME("Not supported with fixed up depth stencil.\n"); 05666 return; 05667 } 05668 05669 if (surface->flags & SFLAG_LOST) 05670 { 05671 TRACE("Surface was discarded, no need copy data.\n"); 05672 switch (location) 05673 { 05674 case SFLAG_INTEXTURE: 05675 surface_prepare_texture(surface, context, FALSE); 05676 break; 05677 case SFLAG_INRB_MULTISAMPLE: 05678 surface_prepare_rb(surface, context->gl_info, TRUE); 05679 break; 05680 case SFLAG_INDRAWABLE: 05681 /* Nothing to do */ 05682 break; 05683 default: 05684 FIXME("Unhandled location %#x\n", location); 05685 } 05686 surface->flags &= ~SFLAG_LOST; 05687 surface->flags |= location; 05688 surface->ds_current_size.cx = surface->resource.width; 05689 surface->ds_current_size.cy = surface->resource.height; 05690 return; 05691 } 05692 05693 if (!(surface->flags & SFLAG_LOCATIONS)) 05694 { 05695 FIXME("No up to date depth stencil location.\n"); 05696 surface->flags |= location; 05697 surface->ds_current_size.cx = surface->resource.width; 05698 surface->ds_current_size.cy = surface->resource.height; 05699 return; 05700 } 05701 05702 if (location == SFLAG_INTEXTURE) 05703 { 05704 GLint old_binding = 0; 05705 GLenum bind_target; 05706 05707 /* The render target is allowed to be smaller than the depth/stencil 05708 * buffer, so the onscreen depth/stencil buffer is potentially smaller 05709 * than the offscreen surface. Don't overwrite the offscreen surface 05710 * with undefined data. */ 05711 w = min(w, context->swapchain->desc.backbuffer_width); 05712 h = min(h, context->swapchain->desc.backbuffer_height); 05713 05714 TRACE("Copying onscreen depth buffer to depth texture.\n"); 05715 05716 ENTER_GL(); 05717 05718 if (!device->depth_blt_texture) 05719 { 05720 glGenTextures(1, &device->depth_blt_texture); 05721 } 05722 05723 /* Note that we use depth_blt here as well, rather than glCopyTexImage2D 05724 * directly on the FBO texture. That's because we need to flip. */ 05725 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER, 05726 context->swapchain->front_buffer, NULL, SFLAG_INDRAWABLE); 05727 if (surface->texture_target == GL_TEXTURE_RECTANGLE_ARB) 05728 { 05729 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding); 05730 bind_target = GL_TEXTURE_RECTANGLE_ARB; 05731 } 05732 else 05733 { 05734 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding); 05735 bind_target = GL_TEXTURE_2D; 05736 } 05737 glBindTexture(bind_target, device->depth_blt_texture); 05738 /* We use GL_DEPTH_COMPONENT instead of the surface's specific 05739 * internal format, because the internal format might include stencil 05740 * data. In principle we should copy stencil data as well, but unless 05741 * the driver supports stencil export it's hard to do, and doesn't 05742 * seem to be needed in practice. If the hardware doesn't support 05743 * writing stencil data, the glCopyTexImage2D() call might trigger 05744 * software fallbacks. */ 05745 glCopyTexImage2D(bind_target, 0, GL_DEPTH_COMPONENT, 0, 0, w, h, 0); 05746 glTexParameteri(bind_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 05747 glTexParameteri(bind_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 05748 glTexParameteri(bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 05749 glTexParameteri(bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 05750 glTexParameteri(bind_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); 05751 glTexParameteri(bind_target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE); 05752 glBindTexture(bind_target, old_binding); 05753 05754 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER, 05755 NULL, surface, SFLAG_INTEXTURE); 05756 context_set_draw_buffer(context, GL_NONE); 05757 glReadBuffer(GL_NONE); 05758 05759 /* Do the actual blit */ 05760 surface_depth_blt(surface, context, device->depth_blt_texture, 0, 0, w, h, bind_target); 05761 checkGLcall("depth_blt"); 05762 05763 context_invalidate_state(context, STATE_FRAMEBUFFER); 05764 05765 LEAVE_GL(); 05766 05767 if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */ 05768 } 05769 else if (location == SFLAG_INDRAWABLE) 05770 { 05771 TRACE("Copying depth texture to onscreen depth buffer.\n"); 05772 05773 ENTER_GL(); 05774 05775 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER, 05776 context->swapchain->front_buffer, NULL, SFLAG_INDRAWABLE); 05777 surface_depth_blt(surface, context, surface->texture_name, 05778 0, surface->pow2Height - h, w, h, surface->texture_target); 05779 checkGLcall("depth_blt"); 05780 05781 context_invalidate_state(context, STATE_FRAMEBUFFER); 05782 05783 LEAVE_GL(); 05784 05785 if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */ 05786 } 05787 else 05788 { 05789 ERR("Invalid location (%#x) specified.\n", location); 05790 } 05791 05792 surface->flags |= location; 05793 surface->ds_current_size.cx = surface->resource.width; 05794 surface->ds_current_size.cy = surface->resource.height; 05795 } 05796 05797 void surface_modify_location(struct wined3d_surface *surface, DWORD location, BOOL persistent) 05798 { 05799 const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info; 05800 struct wined3d_surface *overlay; 05801 05802 TRACE("surface %p, location %s, persistent %#x.\n", 05803 surface, debug_surflocation(location), persistent); 05804 05805 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && surface_is_offscreen(surface) 05806 && !(surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) 05807 && (location & SFLAG_INDRAWABLE)) 05808 ERR("Trying to invalidate the SFLAG_INDRAWABLE location of an offscreen surface.\n"); 05809 05810 if (location & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX) 05811 && gl_info->supported[EXT_TEXTURE_SRGB_DECODE]) 05812 location |= (SFLAG_INTEXTURE | SFLAG_INSRGBTEX); 05813 05814 if (persistent) 05815 { 05816 if (((surface->flags & SFLAG_INTEXTURE) && !(location & SFLAG_INTEXTURE)) 05817 || ((surface->flags & SFLAG_INSRGBTEX) && !(location & SFLAG_INSRGBTEX))) 05818 { 05819 if (surface->container.type == WINED3D_CONTAINER_TEXTURE) 05820 { 05821 TRACE("Passing to container.\n"); 05822 wined3d_texture_set_dirty(surface->container.u.texture, TRUE); 05823 } 05824 } 05825 surface->flags &= ~SFLAG_LOCATIONS; 05826 surface->flags |= location; 05827 05828 /* Redraw emulated overlays, if any */ 05829 if (location & SFLAG_INDRAWABLE && !list_empty(&surface->overlays)) 05830 { 05831 LIST_FOR_EACH_ENTRY(overlay, &surface->overlays, struct wined3d_surface, overlay_entry) 05832 { 05833 surface_draw_overlay(overlay); 05834 } 05835 } 05836 } 05837 else 05838 { 05839 if ((surface->flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)) && (location & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX))) 05840 { 05841 if (surface->container.type == WINED3D_CONTAINER_TEXTURE) 05842 { 05843 TRACE("Passing to container\n"); 05844 wined3d_texture_set_dirty(surface->container.u.texture, TRUE); 05845 } 05846 } 05847 surface->flags &= ~location; 05848 } 05849 05850 if (!(surface->flags & SFLAG_LOCATIONS)) 05851 { 05852 ERR("Surface %p does not have any up to date location.\n", surface); 05853 } 05854 } 05855 05856 static DWORD resource_access_from_location(DWORD location) 05857 { 05858 switch (location) 05859 { 05860 case SFLAG_INSYSMEM: 05861 return WINED3D_RESOURCE_ACCESS_CPU; 05862 05863 case SFLAG_INDRAWABLE: 05864 case SFLAG_INSRGBTEX: 05865 case SFLAG_INTEXTURE: 05866 case SFLAG_INRB_MULTISAMPLE: 05867 case SFLAG_INRB_RESOLVED: 05868 return WINED3D_RESOURCE_ACCESS_GPU; 05869 05870 default: 05871 FIXME("Unhandled location %#x.\n", location); 05872 return 0; 05873 } 05874 } 05875 05876 static void surface_load_sysmem(struct wined3d_surface *surface, 05877 const struct wined3d_gl_info *gl_info, const RECT *rect) 05878 { 05879 surface_prepare_system_memory(surface); 05880 05881 if (surface->flags & (SFLAG_INRB_MULTISAMPLE | SFLAG_INRB_RESOLVED)) 05882 surface_load_location(surface, SFLAG_INTEXTURE, NULL); 05883 05884 /* Download the surface to system memory. */ 05885 if (surface->flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)) 05886 { 05887 struct wined3d_device *device = surface->resource.device; 05888 struct wined3d_context *context; 05889 05890 /* TODO: Use already acquired context when possible. */ 05891 context = context_acquire(device, NULL); 05892 05893 surface_bind_and_dirtify(surface, context, !(surface->flags & SFLAG_INTEXTURE)); 05894 surface_download_data(surface, gl_info); 05895 05896 context_release(context); 05897 05898 return; 05899 } 05900 05901 if (surface->flags & SFLAG_INDRAWABLE) 05902 { 05903 read_from_framebuffer(surface, rect, surface->resource.allocatedMemory, 05904 wined3d_surface_get_pitch(surface)); 05905 return; 05906 } 05907 05908 FIXME("Can't load surface %p with location flags %#x into sysmem.\n", 05909 surface, surface->flags & SFLAG_LOCATIONS); 05910 } 05911 05912 static HRESULT surface_load_drawable(struct wined3d_surface *surface, 05913 const struct wined3d_gl_info *gl_info, const RECT *rect) 05914 { 05915 struct wined3d_device *device = surface->resource.device; 05916 struct wined3d_format format; 05917 CONVERT_TYPES convert; 05918 UINT byte_count; 05919 BYTE *mem; 05920 05921 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && surface_is_offscreen(surface)) 05922 { 05923 ERR("Trying to load offscreen surface into SFLAG_INDRAWABLE.\n"); 05924 return WINED3DERR_INVALIDCALL; 05925 } 05926 05927 if (wined3d_settings.rendertargetlock_mode == RTL_READTEX) 05928 surface_load_location(surface, SFLAG_INTEXTURE, NULL); 05929 05930 if (surface->flags & SFLAG_INTEXTURE) 05931 { 05932 RECT r; 05933 05934 surface_get_rect(surface, rect, &r); 05935 surface_blt_to_drawable(device, WINED3D_TEXF_POINT, FALSE, surface, &r, surface, &r); 05936 05937 return WINED3D_OK; 05938 } 05939 05940 if ((surface->flags & SFLAG_LOCATIONS) == SFLAG_INSRGBTEX) 05941 { 05942 /* This needs colorspace conversion from sRGB to RGB. We take the slow 05943 * path through sysmem. */ 05944 surface_load_location(surface, SFLAG_INSYSMEM, rect); 05945 } 05946 05947 d3dfmt_get_conv(surface, FALSE, FALSE, &format, &convert); 05948 05949 /* Don't use PBOs for converted surfaces. During PBO conversion we look at 05950 * SFLAG_CONVERTED but it isn't set (yet) in all cases where it is getting 05951 * called. */ 05952 if ((convert != NO_CONVERSION) && (surface->flags & SFLAG_PBO)) 05953 { 05954 struct wined3d_context *context; 05955 05956 TRACE("Removing the pbo attached to surface %p.\n", surface); 05957 05958 /* TODO: Use already acquired context when possible. */ 05959 context = context_acquire(device, NULL); 05960 05961 surface_remove_pbo(surface, gl_info); 05962 05963 context_release(context); 05964 } 05965 05966 if ((convert != NO_CONVERSION) && surface->resource.allocatedMemory) 05967 { 05968 UINT height = surface->resource.height; 05969 UINT width = surface->resource.width; 05970 UINT src_pitch, dst_pitch; 05971 05972 byte_count = format.conv_byte_count; 05973 src_pitch = wined3d_surface_get_pitch(surface); 05974 05975 /* Stick to the alignment for the converted surface too, makes it 05976 * easier to load the surface. */ 05977 dst_pitch = width * byte_count; 05978 dst_pitch = (dst_pitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1); 05979 05980 if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_pitch * height))) 05981 { 05982 ERR("Out of memory (%u).\n", dst_pitch * height); 05983 return E_OUTOFMEMORY; 05984 } 05985 05986 d3dfmt_convert_surface(surface->resource.allocatedMemory, mem, 05987 src_pitch, width, height, dst_pitch, convert, surface); 05988 05989 surface->flags |= SFLAG_CONVERTED; 05990 } 05991 else 05992 { 05993 surface->flags &= ~SFLAG_CONVERTED; 05994 mem = surface->resource.allocatedMemory; 05995 byte_count = format.byte_count; 05996 } 05997 05998 flush_to_framebuffer_drawpixels(surface, rect, format.glFormat, format.glType, byte_count, mem); 05999 06000 /* Don't delete PBO memory. */ 06001 if ((mem != surface->resource.allocatedMemory) && !(surface->flags & SFLAG_PBO)) 06002 HeapFree(GetProcessHeap(), 0, mem); 06003 06004 return WINED3D_OK; 06005 } 06006 06007 static HRESULT surface_load_texture(struct wined3d_surface *surface, 06008 const struct wined3d_gl_info *gl_info, const RECT *rect, BOOL srgb) 06009 { 06010 RECT src_rect = {0, 0, surface->resource.width, surface->resource.height}; 06011 struct wined3d_device *device = surface->resource.device; 06012 struct wined3d_context *context; 06013 UINT width, src_pitch, dst_pitch; 06014 struct wined3d_bo_address data; 06015 struct wined3d_format format; 06016 POINT dst_point = {0, 0}; 06017 CONVERT_TYPES convert; 06018 BYTE *mem; 06019 06020 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO 06021 && surface_is_offscreen(surface) 06022 && (surface->flags & SFLAG_INDRAWABLE)) 06023 { 06024 surface_load_fb_texture(surface, srgb); 06025 06026 return WINED3D_OK; 06027 } 06028 06029 if (surface->flags & (SFLAG_INSRGBTEX | SFLAG_INTEXTURE) 06030 && (surface->resource.format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB) 06031 && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT, 06032 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format, 06033 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format)) 06034 { 06035 if (srgb) 06036 surface_blt_fbo(device, WINED3D_TEXF_POINT, surface, SFLAG_INTEXTURE, 06037 &src_rect, surface, SFLAG_INSRGBTEX, &src_rect); 06038 else 06039 surface_blt_fbo(device, WINED3D_TEXF_POINT, surface, SFLAG_INSRGBTEX, 06040 &src_rect, surface, SFLAG_INTEXTURE, &src_rect); 06041 06042 return WINED3D_OK; 06043 } 06044 06045 if (surface->flags & (SFLAG_INRB_MULTISAMPLE | SFLAG_INRB_RESOLVED) 06046 && (!srgb || (surface->resource.format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB)) 06047 && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT, 06048 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format, 06049 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format)) 06050 { 06051 DWORD src_location = surface->flags & SFLAG_INRB_RESOLVED ? SFLAG_INRB_RESOLVED : SFLAG_INRB_MULTISAMPLE; 06052 DWORD dst_location = srgb ? SFLAG_INSRGBTEX : SFLAG_INTEXTURE; 06053 RECT rect = {0, 0, surface->resource.width, surface->resource.height}; 06054 06055 surface_blt_fbo(device, WINED3D_TEXF_POINT, surface, src_location, 06056 &rect, surface, dst_location, &rect); 06057 06058 return WINED3D_OK; 06059 } 06060 06061 /* Upload from system memory */ 06062 06063 d3dfmt_get_conv(surface, TRUE /* We need color keying */, 06064 TRUE /* We will use textures */, &format, &convert); 06065 06066 if (srgb) 06067 { 06068 if ((surface->flags & (SFLAG_INTEXTURE | SFLAG_INSYSMEM)) == SFLAG_INTEXTURE) 06069 { 06070 /* Performance warning... */ 06071 FIXME("Downloading RGB surface %p to reload it as sRGB.\n", surface); 06072 surface_load_location(surface, SFLAG_INSYSMEM, rect); 06073 } 06074 } 06075 else 06076 { 06077 if ((surface->flags & (SFLAG_INSRGBTEX | SFLAG_INSYSMEM)) == SFLAG_INSRGBTEX) 06078 { 06079 /* Performance warning... */ 06080 FIXME("Downloading sRGB surface %p to reload it as RGB.\n", surface); 06081 surface_load_location(surface, SFLAG_INSYSMEM, rect); 06082 } 06083 } 06084 06085 if (!(surface->flags & SFLAG_INSYSMEM)) 06086 { 06087 WARN("Trying to load a texture from sysmem, but SFLAG_INSYSMEM is not set.\n"); 06088 /* Lets hope we get it from somewhere... */ 06089 surface_load_location(surface, SFLAG_INSYSMEM, rect); 06090 } 06091 06092 /* TODO: Use already acquired context when possible. */ 06093 context = context_acquire(device, NULL); 06094 06095 surface_prepare_texture(surface, context, srgb); 06096 surface_bind_and_dirtify(surface, context, srgb); 06097 06098 if (surface->CKeyFlags & WINEDDSD_CKSRCBLT) 06099 { 06100 surface->flags |= SFLAG_GLCKEY; 06101 surface->gl_color_key = surface->src_blt_color_key; 06102 } 06103 else surface->flags &= ~SFLAG_GLCKEY; 06104 06105 width = surface->resource.width; 06106 src_pitch = wined3d_surface_get_pitch(surface); 06107 06108 /* Don't use PBOs for converted surfaces. During PBO conversion we look at 06109 * SFLAG_CONVERTED but it isn't set (yet) in all cases it is getting 06110 * called. */ 06111 if ((convert != NO_CONVERSION || format.convert) && (surface->flags & SFLAG_PBO)) 06112 { 06113 TRACE("Removing the pbo attached to surface %p.\n", surface); 06114 surface_remove_pbo(surface, gl_info); 06115 } 06116 06117 if (format.convert) 06118 { 06119 /* This code is entered for texture formats which need a fixup. */ 06120 UINT height = surface->resource.height; 06121 06122 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */ 06123 dst_pitch = width * format.conv_byte_count; 06124 dst_pitch = (dst_pitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1); 06125 06126 if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_pitch * height))) 06127 { 06128 ERR("Out of memory (%u).\n", dst_pitch * height); 06129 context_release(context); 06130 return E_OUTOFMEMORY; 06131 } 06132 format.convert(surface->resource.allocatedMemory, mem, src_pitch, width, height); 06133 format.byte_count = format.conv_byte_count; 06134 src_pitch = dst_pitch; 06135 } 06136 else if (convert != NO_CONVERSION && surface->resource.allocatedMemory) 06137 { 06138 /* This code is only entered for color keying fixups */ 06139 UINT height = surface->resource.height; 06140 06141 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */ 06142 dst_pitch = width * format.conv_byte_count; 06143 dst_pitch = (dst_pitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1); 06144 06145 if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_pitch * height))) 06146 { 06147 ERR("Out of memory (%u).\n", dst_pitch * height); 06148 context_release(context); 06149 return E_OUTOFMEMORY; 06150 } 06151 d3dfmt_convert_surface(surface->resource.allocatedMemory, mem, src_pitch, 06152 width, height, dst_pitch, convert, surface); 06153 format.byte_count = format.conv_byte_count; 06154 src_pitch = dst_pitch; 06155 } 06156 else 06157 { 06158 mem = surface->resource.allocatedMemory; 06159 } 06160 06161 data.buffer_object = surface->flags & SFLAG_PBO ? surface->pbo : 0; 06162 data.addr = mem; 06163 surface_upload_data(surface, gl_info, &format, &src_rect, src_pitch, &dst_point, srgb, &data); 06164 06165 context_release(context); 06166 06167 /* Don't delete PBO memory. */ 06168 if ((mem != surface->resource.allocatedMemory) && !(surface->flags & SFLAG_PBO)) 06169 HeapFree(GetProcessHeap(), 0, mem); 06170 06171 return WINED3D_OK; 06172 } 06173 06174 static void surface_multisample_resolve(struct wined3d_surface *surface) 06175 { 06176 RECT rect = {0, 0, surface->resource.width, surface->resource.height}; 06177 06178 if (!(surface->flags & SFLAG_INRB_MULTISAMPLE)) 06179 ERR("Trying to resolve multisampled surface %p, but location SFLAG_INRB_MULTISAMPLE not current.\n", surface); 06180 06181 surface_blt_fbo(surface->resource.device, WINED3D_TEXF_POINT, 06182 surface, SFLAG_INRB_MULTISAMPLE, &rect, surface, SFLAG_INRB_RESOLVED, &rect); 06183 } 06184 06185 HRESULT surface_load_location(struct wined3d_surface *surface, DWORD location, const RECT *rect) 06186 { 06187 struct wined3d_device *device = surface->resource.device; 06188 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; 06189 HRESULT hr; 06190 06191 TRACE("surface %p, location %s, rect %s.\n", surface, debug_surflocation(location), wine_dbgstr_rect(rect)); 06192 06193 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) 06194 { 06195 if (location == SFLAG_INTEXTURE) 06196 { 06197 struct wined3d_context *context = context_acquire(device, NULL); 06198 surface_load_ds_location(surface, context, location); 06199 context_release(context); 06200 return WINED3D_OK; 06201 } 06202 else 06203 { 06204 FIXME("Unimplemented location %s for depth/stencil buffers.\n", debug_surflocation(location)); 06205 return WINED3DERR_INVALIDCALL; 06206 } 06207 } 06208 06209 if (location == SFLAG_INSRGBTEX && gl_info->supported[EXT_TEXTURE_SRGB_DECODE]) 06210 location = SFLAG_INTEXTURE; 06211 06212 if (surface->flags & location) 06213 { 06214 TRACE("Location already up to date.\n"); 06215 06216 if (location == SFLAG_INSYSMEM && !(surface->flags & SFLAG_PBO) 06217 && surface_need_pbo(surface, gl_info)) 06218 surface_load_pbo(surface, gl_info); 06219 06220 return WINED3D_OK; 06221 } 06222 06223 if (WARN_ON(d3d_surface)) 06224 { 06225 DWORD required_access = resource_access_from_location(location); 06226 if ((surface->resource.access_flags & required_access) != required_access) 06227 WARN("Operation requires %#x access, but surface only has %#x.\n", 06228 required_access, surface->resource.access_flags); 06229 } 06230 06231 if (!(surface->flags & SFLAG_LOCATIONS)) 06232 { 06233 ERR("Surface %p does not have any up to date location.\n", surface); 06234 surface->flags |= SFLAG_LOST; 06235 return WINED3DERR_DEVICELOST; 06236 } 06237 06238 switch (location) 06239 { 06240 case SFLAG_INSYSMEM: 06241 surface_load_sysmem(surface, gl_info, rect); 06242 break; 06243 06244 case SFLAG_INDRAWABLE: 06245 if (FAILED(hr = surface_load_drawable(surface, gl_info, rect))) 06246 return hr; 06247 break; 06248 06249 case SFLAG_INRB_RESOLVED: 06250 surface_multisample_resolve(surface); 06251 break; 06252 06253 case SFLAG_INTEXTURE: 06254 case SFLAG_INSRGBTEX: 06255 if (FAILED(hr = surface_load_texture(surface, gl_info, rect, location == SFLAG_INSRGBTEX))) 06256 return hr; 06257 break; 06258 06259 default: 06260 ERR("Don't know how to handle location %#x.\n", location); 06261 break; 06262 } 06263 06264 if (!rect) 06265 { 06266 surface->flags |= location; 06267 06268 if (location != SFLAG_INSYSMEM && (surface->flags & SFLAG_INSYSMEM)) 06269 surface_evict_sysmem(surface); 06270 } 06271 06272 if (surface->flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX) 06273 && gl_info->supported[EXT_TEXTURE_SRGB_DECODE]) 06274 { 06275 surface->flags |= (SFLAG_INTEXTURE | SFLAG_INSRGBTEX); 06276 } 06277 06278 return WINED3D_OK; 06279 } 06280 06281 BOOL surface_is_offscreen(const struct wined3d_surface *surface) 06282 { 06283 struct wined3d_swapchain *swapchain = surface->container.u.swapchain; 06284 06285 /* Not on a swapchain - must be offscreen */ 06286 if (surface->container.type != WINED3D_CONTAINER_SWAPCHAIN) return TRUE; 06287 06288 /* The front buffer is always onscreen */ 06289 if (surface == swapchain->front_buffer) return FALSE; 06290 06291 /* If the swapchain is rendered to an FBO, the backbuffer is 06292 * offscreen, otherwise onscreen */ 06293 return swapchain->render_to_fbo; 06294 } 06295 06296 static HRESULT ffp_blit_alloc(struct wined3d_device *device) { return WINED3D_OK; } 06297 /* Context activation is done by the caller. */ 06298 static void ffp_blit_free(struct wined3d_device *device) { } 06299 06300 /* This function is used in case of 8bit paletted textures using GL_EXT_paletted_texture */ 06301 /* Context activation is done by the caller. */ 06302 static void ffp_blit_p8_upload_palette(const struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info) 06303 { 06304 BYTE table[256][4]; 06305 BOOL colorkey_active = (surface->CKeyFlags & WINEDDSD_CKSRCBLT) ? TRUE : FALSE; 06306 06307 d3dfmt_p8_init_palette(surface, table, colorkey_active); 06308 06309 TRACE("Using GL_EXT_PALETTED_TEXTURE for 8-bit paletted texture support\n"); 06310 ENTER_GL(); 06311 GL_EXTCALL(glColorTableEXT(surface->texture_target, GL_RGBA, 256, GL_RGBA, GL_UNSIGNED_BYTE, table)); 06312 LEAVE_GL(); 06313 } 06314 06315 /* Context activation is done by the caller. */ 06316 static HRESULT ffp_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface) 06317 { 06318 enum complex_fixup fixup = get_complex_fixup(surface->resource.format->color_fixup); 06319 06320 /* When EXT_PALETTED_TEXTURE is around, palette conversion is done by the GPU 06321 * else the surface is converted in software at upload time in LoadLocation. 06322 */ 06323 if (!(surface->flags & SFLAG_CONVERTED) && fixup == COMPLEX_FIXUP_P8 06324 && context->gl_info->supported[EXT_PALETTED_TEXTURE]) 06325 ffp_blit_p8_upload_palette(surface, context->gl_info); 06326 06327 ENTER_GL(); 06328 glEnable(surface->texture_target); 06329 checkGLcall("glEnable(surface->texture_target)"); 06330 LEAVE_GL(); 06331 return WINED3D_OK; 06332 } 06333 06334 /* Context activation is done by the caller. */ 06335 static void ffp_blit_unset(const struct wined3d_gl_info *gl_info) 06336 { 06337 ENTER_GL(); 06338 glDisable(GL_TEXTURE_2D); 06339 checkGLcall("glDisable(GL_TEXTURE_2D)"); 06340 if (gl_info->supported[ARB_TEXTURE_CUBE_MAP]) 06341 { 06342 glDisable(GL_TEXTURE_CUBE_MAP_ARB); 06343 checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)"); 06344 } 06345 if (gl_info->supported[ARB_TEXTURE_RECTANGLE]) 06346 { 06347 glDisable(GL_TEXTURE_RECTANGLE_ARB); 06348 checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)"); 06349 } 06350 LEAVE_GL(); 06351 } 06352 06353 static BOOL ffp_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op, 06354 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format, 06355 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format) 06356 { 06357 enum complex_fixup src_fixup; 06358 06359 switch (blit_op) 06360 { 06361 case WINED3D_BLIT_OP_COLOR_BLIT: 06362 if (src_pool == WINED3D_POOL_SYSTEM_MEM || dst_pool == WINED3D_POOL_SYSTEM_MEM) 06363 return FALSE; 06364 06365 src_fixup = get_complex_fixup(src_format->color_fixup); 06366 if (TRACE_ON(d3d_surface) && TRACE_ON(d3d)) 06367 { 06368 TRACE("Checking support for fixup:\n"); 06369 dump_color_fixup_desc(src_format->color_fixup); 06370 } 06371 06372 if (!is_identity_fixup(dst_format->color_fixup)) 06373 { 06374 TRACE("Destination fixups are not supported\n"); 06375 return FALSE; 06376 } 06377 06378 if (src_fixup == COMPLEX_FIXUP_P8 && gl_info->supported[EXT_PALETTED_TEXTURE]) 06379 { 06380 TRACE("P8 fixup supported\n"); 06381 return TRUE; 06382 } 06383 06384 /* We only support identity conversions. */ 06385 if (is_identity_fixup(src_format->color_fixup)) 06386 { 06387 TRACE("[OK]\n"); 06388 return TRUE; 06389 } 06390 06391 TRACE("[FAILED]\n"); 06392 return FALSE; 06393 06394 case WINED3D_BLIT_OP_COLOR_FILL: 06395 if (dst_pool == WINED3D_POOL_SYSTEM_MEM) 06396 return FALSE; 06397 06398 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) 06399 { 06400 if (!((dst_format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE) || (dst_usage & WINED3DUSAGE_RENDERTARGET))) 06401 return FALSE; 06402 } 06403 else if (!(dst_usage & WINED3DUSAGE_RENDERTARGET)) 06404 { 06405 TRACE("Color fill not supported\n"); 06406 return FALSE; 06407 } 06408 06409 /* FIXME: We should reject color fills on formats with fixups, 06410 * but this would break P8 color fills for example. */ 06411 06412 return TRUE; 06413 06414 case WINED3D_BLIT_OP_DEPTH_FILL: 06415 return TRUE; 06416 06417 default: 06418 TRACE("Unsupported blit_op=%d\n", blit_op); 06419 return FALSE; 06420 } 06421 } 06422 06423 /* Do not call while under the GL lock. */ 06424 static HRESULT ffp_blit_color_fill(struct wined3d_device *device, struct wined3d_surface *dst_surface, 06425 const RECT *dst_rect, const struct wined3d_color *color) 06426 { 06427 const RECT draw_rect = {0, 0, dst_surface->resource.width, dst_surface->resource.height}; 06428 struct wined3d_fb_state fb = {&dst_surface, NULL}; 06429 06430 return device_clear_render_targets(device, 1, &fb, 06431 1, dst_rect, &draw_rect, WINED3DCLEAR_TARGET, color, 0.0f, 0); 06432 } 06433 06434 /* Do not call while under the GL lock. */ 06435 static HRESULT ffp_blit_depth_fill(struct wined3d_device *device, 06436 struct wined3d_surface *surface, const RECT *rect, float depth) 06437 { 06438 const RECT draw_rect = {0, 0, surface->resource.width, surface->resource.height}; 06439 struct wined3d_fb_state fb = {NULL, surface}; 06440 06441 return device_clear_render_targets(device, 0, &fb, 06442 1, rect, &draw_rect, WINED3DCLEAR_ZBUFFER, 0, depth, 0); 06443 } 06444 06445 const struct blit_shader ffp_blit = { 06446 ffp_blit_alloc, 06447 ffp_blit_free, 06448 ffp_blit_set, 06449 ffp_blit_unset, 06450 ffp_blit_supported, 06451 ffp_blit_color_fill, 06452 ffp_blit_depth_fill, 06453 }; 06454 06455 static HRESULT cpu_blit_alloc(struct wined3d_device *device) 06456 { 06457 return WINED3D_OK; 06458 } 06459 06460 /* Context activation is done by the caller. */ 06461 static void cpu_blit_free(struct wined3d_device *device) 06462 { 06463 } 06464 06465 /* Context activation is done by the caller. */ 06466 static HRESULT cpu_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface) 06467 { 06468 return WINED3D_OK; 06469 } 06470 06471 /* Context activation is done by the caller. */ 06472 static void cpu_blit_unset(const struct wined3d_gl_info *gl_info) 06473 { 06474 } 06475 06476 static BOOL cpu_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op, 06477 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format, 06478 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format) 06479 { 06480 if (blit_op == WINED3D_BLIT_OP_COLOR_FILL) 06481 { 06482 return TRUE; 06483 } 06484 06485 return FALSE; 06486 } 06487 06488 static HRESULT surface_cpu_blt_compressed(const BYTE *src_data, BYTE *dst_data, 06489 UINT src_pitch, UINT dst_pitch, UINT update_w, UINT update_h, 06490 const struct wined3d_format *format, DWORD flags, const WINEDDBLTFX *fx) 06491 { 06492 UINT row_block_count; 06493 const BYTE *src_row; 06494 BYTE *dst_row; 06495 UINT x, y; 06496 06497 src_row = src_data; 06498 dst_row = dst_data; 06499 06500 row_block_count = (update_w + format->block_width - 1) / format->block_width; 06501 06502 if (!flags) 06503 { 06504 for (y = 0; y < update_h; y += format->block_height) 06505 { 06506 memcpy(dst_row, src_row, row_block_count * format->block_byte_count); 06507 src_row += src_pitch; 06508 dst_row += dst_pitch; 06509 } 06510 06511 return WINED3D_OK; 06512 } 06513 06514 if (flags == WINEDDBLT_DDFX && fx->dwDDFX == WINEDDBLTFX_MIRRORUPDOWN) 06515 { 06516 src_row += (((update_h / format->block_height) - 1) * src_pitch); 06517 06518 switch (format->id) 06519 { 06520 case WINED3DFMT_DXT1: 06521 for (y = 0; y < update_h; y += format->block_height) 06522 { 06523 struct block 06524 { 06525 WORD color[2]; 06526 BYTE control_row[4]; 06527 }; 06528 06529 const struct block *s = (const struct block *)src_row; 06530 struct block *d = (struct block *)dst_row; 06531 06532 for (x = 0; x < row_block_count; ++x) 06533 { 06534 d[x].color[0] = s[x].color[0]; 06535 d[x].color[1] = s[x].color[1]; 06536 d[x].control_row[0] = s[x].control_row[3]; 06537 d[x].control_row[1] = s[x].control_row[2]; 06538 d[x].control_row[2] = s[x].control_row[1]; 06539 d[x].control_row[3] = s[x].control_row[0]; 06540 } 06541 src_row -= src_pitch; 06542 dst_row += dst_pitch; 06543 } 06544 return WINED3D_OK; 06545 06546 case WINED3DFMT_DXT3: 06547 for (y = 0; y < update_h; y += format->block_height) 06548 { 06549 struct block 06550 { 06551 WORD alpha_row[4]; 06552 WORD color[2]; 06553 BYTE control_row[4]; 06554 }; 06555 06556 const struct block *s = (const struct block *)src_row; 06557 struct block *d = (struct block *)dst_row; 06558 06559 for (x = 0; x < row_block_count; ++x) 06560 { 06561 d[x].alpha_row[0] = s[x].alpha_row[3]; 06562 d[x].alpha_row[1] = s[x].alpha_row[2]; 06563 d[x].alpha_row[2] = s[x].alpha_row[1]; 06564 d[x].alpha_row[3] = s[x].alpha_row[0]; 06565 d[x].color[0] = s[x].color[0]; 06566 d[x].color[1] = s[x].color[1]; 06567 d[x].control_row[0] = s[x].control_row[3]; 06568 d[x].control_row[1] = s[x].control_row[2]; 06569 d[x].control_row[2] = s[x].control_row[1]; 06570 d[x].control_row[3] = s[x].control_row[0]; 06571 } 06572 src_row -= src_pitch; 06573 dst_row += dst_pitch; 06574 } 06575 return WINED3D_OK; 06576 06577 default: 06578 FIXME("Compressed flip not implemented for format %s.\n", 06579 debug_d3dformat(format->id)); 06580 return E_NOTIMPL; 06581 } 06582 } 06583 06584 FIXME("Unsupported blit on compressed surface (format %s, flags %#x, DDFX %#x).\n", 06585 debug_d3dformat(format->id), flags, flags & WINEDDBLT_DDFX ? fx->dwDDFX : 0); 06586 06587 return E_NOTIMPL; 06588 } 06589 06590 static HRESULT surface_cpu_blt(struct wined3d_surface *dst_surface, const RECT *dst_rect, 06591 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags, 06592 const WINEDDBLTFX *fx, enum wined3d_texture_filter_type filter) 06593 { 06594 int bpp, srcheight, srcwidth, dstheight, dstwidth, width; 06595 const struct wined3d_format *src_format, *dst_format; 06596 struct wined3d_surface *orig_src = src_surface; 06597 struct wined3d_mapped_rect dst_map, src_map; 06598 HRESULT hr = WINED3D_OK; 06599 const BYTE *sbuf; 06600 RECT xdst,xsrc; 06601 BYTE *dbuf; 06602 int x, y; 06603 06604 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n", 06605 dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect), 06606 flags, fx, debug_d3dtexturefiltertype(filter)); 06607 06608 xsrc = *src_rect; 06609 06610 if (!src_surface) 06611 { 06612 RECT full_rect; 06613 06614 full_rect.left = 0; 06615 full_rect.top = 0; 06616 full_rect.right = dst_surface->resource.width; 06617 full_rect.bottom = dst_surface->resource.height; 06618 IntersectRect(&xdst, &full_rect, dst_rect); 06619 } 06620 else 06621 { 06622 BOOL clip_horiz, clip_vert; 06623 06624 xdst = *dst_rect; 06625 clip_horiz = xdst.left < 0 || xdst.right > (int)dst_surface->resource.width; 06626 clip_vert = xdst.top < 0 || xdst.bottom > (int)dst_surface->resource.height; 06627 06628 if (clip_vert || clip_horiz) 06629 { 06630 /* Now check if this is a special case or not... */ 06631 if ((flags & WINEDDBLT_DDFX) 06632 || (clip_horiz && xdst.right - xdst.left != xsrc.right - xsrc.left) 06633 || (clip_vert && xdst.bottom - xdst.top != xsrc.bottom - xsrc.top)) 06634 { 06635 WARN("Out of screen rectangle in special case. Not handled right now.\n"); 06636 return WINED3D_OK; 06637 } 06638 06639 if (clip_horiz) 06640 { 06641 if (xdst.left < 0) 06642 { 06643 xsrc.left -= xdst.left; 06644 xdst.left = 0; 06645 } 06646 if (xdst.right > dst_surface->resource.width) 06647 { 06648 xsrc.right -= (xdst.right - (int)dst_surface->resource.width); 06649 xdst.right = (int)dst_surface->resource.width; 06650 } 06651 } 06652 06653 if (clip_vert) 06654 { 06655 if (xdst.top < 0) 06656 { 06657 xsrc.top -= xdst.top; 06658 xdst.top = 0; 06659 } 06660 if (xdst.bottom > dst_surface->resource.height) 06661 { 06662 xsrc.bottom -= (xdst.bottom - (int)dst_surface->resource.height); 06663 xdst.bottom = (int)dst_surface->resource.height; 06664 } 06665 } 06666 06667 /* And check if after clipping something is still to be done... */ 06668 if ((xdst.right <= 0) || (xdst.bottom <= 0) 06669 || (xdst.left >= (int)dst_surface->resource.width) 06670 || (xdst.top >= (int)dst_surface->resource.height) 06671 || (xsrc.right <= 0) || (xsrc.bottom <= 0) 06672 || (xsrc.left >= (int)src_surface->resource.width) 06673 || (xsrc.top >= (int)src_surface->resource.height)) 06674 { 06675 TRACE("Nothing to be done after clipping.\n"); 06676 return WINED3D_OK; 06677 } 06678 } 06679 } 06680 06681 if (src_surface == dst_surface) 06682 { 06683 wined3d_surface_map(dst_surface, &dst_map, NULL, 0); 06684 src_map = dst_map; 06685 src_format = dst_surface->resource.format; 06686 dst_format = src_format; 06687 } 06688 else 06689 { 06690 dst_format = dst_surface->resource.format; 06691 if (src_surface) 06692 { 06693 if (dst_surface->resource.format->id != src_surface->resource.format->id) 06694 { 06695 src_surface = surface_convert_format(src_surface, dst_format->id); 06696 if (!src_surface) 06697 { 06698 /* The conv function writes a FIXME */ 06699 WARN("Cannot convert source surface format to dest format.\n"); 06700 goto release; 06701 } 06702 } 06703 wined3d_surface_map(src_surface, &src_map, NULL, WINED3DLOCK_READONLY); 06704 src_format = src_surface->resource.format; 06705 } 06706 else 06707 { 06708 src_format = dst_format; 06709 } 06710 if (dst_rect) 06711 wined3d_surface_map(dst_surface, &dst_map, &xdst, 0); 06712 else 06713 wined3d_surface_map(dst_surface, &dst_map, NULL, 0); 06714 } 06715 06716 bpp = dst_surface->resource.format->byte_count; 06717 srcheight = xsrc.bottom - xsrc.top; 06718 srcwidth = xsrc.right - xsrc.left; 06719 dstheight = xdst.bottom - xdst.top; 06720 dstwidth = xdst.right - xdst.left; 06721 width = (xdst.right - xdst.left) * bpp; 06722 06723 if (src_format->flags & dst_format->flags & WINED3DFMT_FLAG_BLOCKS) 06724 { 06725 TRACE("%s -> %s copy.\n", debug_d3dformat(src_format->id), debug_d3dformat(dst_format->id)); 06726 06727 if (src_surface == dst_surface) 06728 { 06729 FIXME("Only plain blits supported on compressed surfaces.\n"); 06730 hr = E_NOTIMPL; 06731 goto release; 06732 } 06733 06734 if (srcheight != dstheight || srcwidth != dstwidth) 06735 { 06736 WARN("Stretching not supported on compressed surfaces.\n"); 06737 hr = WINED3DERR_INVALIDCALL; 06738 goto release; 06739 } 06740 06741 if (srcwidth & (src_format->block_width - 1) || srcheight & (src_format->block_height - 1)) 06742 { 06743 WARN("Rectangle not block-aligned.\n"); 06744 hr = WINED3DERR_INVALIDCALL; 06745 goto release; 06746 } 06747 06748 hr = surface_cpu_blt_compressed(src_map.data, dst_map.data, 06749 src_map.row_pitch, dst_map.row_pitch, dstwidth, dstheight, 06750 src_format, flags, fx); 06751 goto release; 06752 } 06753 06754 if (dst_rect && src_surface != dst_surface) 06755 dbuf = dst_map.data; 06756 else 06757 dbuf = (BYTE *)dst_map.data + (xdst.top * dst_map.row_pitch) + (xdst.left * bpp); 06758 06759 /* First, all the 'source-less' blits */ 06760 if (flags & WINEDDBLT_COLORFILL) 06761 { 06762 hr = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp, dst_map.row_pitch, fx->u5.dwFillColor); 06763 flags &= ~WINEDDBLT_COLORFILL; 06764 } 06765 06766 if (flags & WINEDDBLT_DEPTHFILL) 06767 { 06768 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n"); 06769 } 06770 if (flags & WINEDDBLT_ROP) 06771 { 06772 /* Catch some degenerate cases here. */ 06773 switch (fx->dwROP) 06774 { 06775 case BLACKNESS: 06776 hr = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp, dst_map.row_pitch, 0); 06777 break; 06778 case 0xAA0029: /* No-op */ 06779 break; 06780 case WHITENESS: 06781 hr = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp, dst_map.row_pitch, ~0U); 06782 break; 06783 case SRCCOPY: /* Well, we do that below? */ 06784 break; 06785 default: 06786 FIXME("Unsupported raster op: %08x Pattern: %p\n", fx->dwROP, fx->u5.lpDDSPattern); 06787 goto error; 06788 } 06789 flags &= ~WINEDDBLT_ROP; 06790 } 06791 if (flags & WINEDDBLT_DDROPS) 06792 { 06793 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", fx->dwDDROP, fx->u5.lpDDSPattern); 06794 } 06795 /* Now the 'with source' blits. */ 06796 if (src_surface) 06797 { 06798 const BYTE *sbase; 06799 int sx, xinc, sy, yinc; 06800 06801 if (!dstwidth || !dstheight) /* Hmm... stupid program? */ 06802 goto release; 06803 06804 if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT 06805 && (srcwidth != dstwidth || srcheight != dstheight)) 06806 { 06807 /* Can happen when d3d9 apps do a StretchRect() call which isn't handled in GL. */ 06808 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(filter)); 06809 } 06810 06811 sbase = (BYTE *)src_map.data + (xsrc.top * src_map.row_pitch) + xsrc.left * bpp; 06812 xinc = (srcwidth << 16) / dstwidth; 06813 yinc = (srcheight << 16) / dstheight; 06814 06815 if (!flags) 06816 { 06817 /* No effects, we can cheat here. */ 06818 if (dstwidth == srcwidth) 06819 { 06820 if (dstheight == srcheight) 06821 { 06822 /* No stretching in either direction. This needs to be as 06823 * fast as possible. */ 06824 sbuf = sbase; 06825 06826 /* Check for overlapping surfaces. */ 06827 if (src_surface != dst_surface || xdst.top < xsrc.top 06828 || xdst.right <= xsrc.left || xsrc.right <= xdst.left) 06829 { 06830 /* No overlap, or dst above src, so copy from top downwards. */ 06831 for (y = 0; y < dstheight; ++y) 06832 { 06833 memcpy(dbuf, sbuf, width); 06834 sbuf += src_map.row_pitch; 06835 dbuf += dst_map.row_pitch; 06836 } 06837 } 06838 else if (xdst.top > xsrc.top) 06839 { 06840 /* Copy from bottom upwards. */ 06841 sbuf += src_map.row_pitch * dstheight; 06842 dbuf += dst_map.row_pitch * dstheight; 06843 for (y = 0; y < dstheight; ++y) 06844 { 06845 sbuf -= src_map.row_pitch; 06846 dbuf -= dst_map.row_pitch; 06847 memcpy(dbuf, sbuf, width); 06848 } 06849 } 06850 else 06851 { 06852 /* Src and dst overlapping on the same line, use memmove. */ 06853 for (y = 0; y < dstheight; ++y) 06854 { 06855 memmove(dbuf, sbuf, width); 06856 sbuf += src_map.row_pitch; 06857 dbuf += dst_map.row_pitch; 06858 } 06859 } 06860 } 06861 else 06862 { 06863 /* Stretching in y direction only. */ 06864 for (y = sy = 0; y < dstheight; ++y, sy += yinc) 06865 { 06866 sbuf = sbase + (sy >> 16) * src_map.row_pitch; 06867 memcpy(dbuf, sbuf, width); 06868 dbuf += dst_map.row_pitch; 06869 } 06870 } 06871 } 06872 else 06873 { 06874 /* Stretching in X direction. */ 06875 int last_sy = -1; 06876 for (y = sy = 0; y < dstheight; ++y, sy += yinc) 06877 { 06878 sbuf = sbase + (sy >> 16) * src_map.row_pitch; 06879 06880 if ((sy >> 16) == (last_sy >> 16)) 06881 { 06882 /* This source row is the same as last source row - 06883 * Copy the already stretched row. */ 06884 memcpy(dbuf, dbuf - dst_map.row_pitch, width); 06885 } 06886 else 06887 { 06888 #define STRETCH_ROW(type) \ 06889 do { \ 06890 const type *s = (const type *)sbuf; \ 06891 type *d = (type *)dbuf; \ 06892 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \ 06893 d[x] = s[sx >> 16]; \ 06894 } while(0) 06895 06896 switch(bpp) 06897 { 06898 case 1: 06899 STRETCH_ROW(BYTE); 06900 break; 06901 case 2: 06902 STRETCH_ROW(WORD); 06903 break; 06904 case 4: 06905 STRETCH_ROW(DWORD); 06906 break; 06907 case 3: 06908 { 06909 const BYTE *s; 06910 BYTE *d = dbuf; 06911 for (x = sx = 0; x < dstwidth; x++, sx+= xinc) 06912 { 06913 DWORD pixel; 06914 06915 s = sbuf + 3 * (sx >> 16); 06916 pixel = s[0] | (s[1] << 8) | (s[2] << 16); 06917 d[0] = (pixel ) & 0xff; 06918 d[1] = (pixel >> 8) & 0xff; 06919 d[2] = (pixel >> 16) & 0xff; 06920 d += 3; 06921 } 06922 break; 06923 } 06924 default: 06925 FIXME("Stretched blit not implemented for bpp %u!\n", bpp * 8); 06926 hr = WINED3DERR_NOTAVAILABLE; 06927 goto error; 06928 } 06929 #undef STRETCH_ROW 06930 } 06931 dbuf += dst_map.row_pitch; 06932 last_sy = sy; 06933 } 06934 } 06935 } 06936 else 06937 { 06938 LONG dstyinc = dst_map.row_pitch, dstxinc = bpp; 06939 DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF; 06940 DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF; 06941 if (flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE)) 06942 { 06943 /* The color keying flags are checked for correctness in ddraw */ 06944 if (flags & WINEDDBLT_KEYSRC) 06945 { 06946 keylow = src_surface->src_blt_color_key.color_space_low_value; 06947 keyhigh = src_surface->src_blt_color_key.color_space_high_value; 06948 } 06949 else if (flags & WINEDDBLT_KEYSRCOVERRIDE) 06950 { 06951 keylow = fx->ddckSrcColorkey.color_space_low_value; 06952 keyhigh = fx->ddckSrcColorkey.color_space_high_value; 06953 } 06954 06955 if (flags & WINEDDBLT_KEYDEST) 06956 { 06957 /* Destination color keys are taken from the source surface! */ 06958 destkeylow = src_surface->dst_blt_color_key.color_space_low_value; 06959 destkeyhigh = src_surface->dst_blt_color_key.color_space_high_value; 06960 } 06961 else if (flags & WINEDDBLT_KEYDESTOVERRIDE) 06962 { 06963 destkeylow = fx->ddckDestColorkey.color_space_low_value; 06964 destkeyhigh = fx->ddckDestColorkey.color_space_high_value; 06965 } 06966 06967 if (bpp == 1) 06968 { 06969 keymask = 0xff; 06970 } 06971 else 06972 { 06973 keymask = src_format->red_mask 06974 | src_format->green_mask 06975 | src_format->blue_mask; 06976 } 06977 flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE); 06978 } 06979 06980 if (flags & WINEDDBLT_DDFX) 06981 { 06982 BYTE *dTopLeft, *dTopRight, *dBottomLeft, *dBottomRight, *tmp; 06983 LONG tmpxy; 06984 dTopLeft = dbuf; 06985 dTopRight = dbuf + ((dstwidth - 1) * bpp); 06986 dBottomLeft = dTopLeft + ((dstheight - 1) * dst_map.row_pitch); 06987 dBottomRight = dBottomLeft + ((dstwidth - 1) * bpp); 06988 06989 if (fx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY) 06990 { 06991 /* I don't think we need to do anything about this flag */ 06992 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n"); 06993 } 06994 if (fx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT) 06995 { 06996 tmp = dTopRight; 06997 dTopRight = dTopLeft; 06998 dTopLeft = tmp; 06999 tmp = dBottomRight; 07000 dBottomRight = dBottomLeft; 07001 dBottomLeft = tmp; 07002 dstxinc = dstxinc * -1; 07003 } 07004 if (fx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN) 07005 { 07006 tmp = dTopLeft; 07007 dTopLeft = dBottomLeft; 07008 dBottomLeft = tmp; 07009 tmp = dTopRight; 07010 dTopRight = dBottomRight; 07011 dBottomRight = tmp; 07012 dstyinc = dstyinc * -1; 07013 } 07014 if (fx->dwDDFX & WINEDDBLTFX_NOTEARING) 07015 { 07016 /* I don't think we need to do anything about this flag */ 07017 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n"); 07018 } 07019 if (fx->dwDDFX & WINEDDBLTFX_ROTATE180) 07020 { 07021 tmp = dBottomRight; 07022 dBottomRight = dTopLeft; 07023 dTopLeft = tmp; 07024 tmp = dBottomLeft; 07025 dBottomLeft = dTopRight; 07026 dTopRight = tmp; 07027 dstxinc = dstxinc * -1; 07028 dstyinc = dstyinc * -1; 07029 } 07030 if (fx->dwDDFX & WINEDDBLTFX_ROTATE270) 07031 { 07032 tmp = dTopLeft; 07033 dTopLeft = dBottomLeft; 07034 dBottomLeft = dBottomRight; 07035 dBottomRight = dTopRight; 07036 dTopRight = tmp; 07037 tmpxy = dstxinc; 07038 dstxinc = dstyinc; 07039 dstyinc = tmpxy; 07040 dstxinc = dstxinc * -1; 07041 } 07042 if (fx->dwDDFX & WINEDDBLTFX_ROTATE90) 07043 { 07044 tmp = dTopLeft; 07045 dTopLeft = dTopRight; 07046 dTopRight = dBottomRight; 07047 dBottomRight = dBottomLeft; 07048 dBottomLeft = tmp; 07049 tmpxy = dstxinc; 07050 dstxinc = dstyinc; 07051 dstyinc = tmpxy; 07052 dstyinc = dstyinc * -1; 07053 } 07054 if (fx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST) 07055 { 07056 /* I don't think we need to do anything about this flag */ 07057 WARN("flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n"); 07058 } 07059 dbuf = dTopLeft; 07060 flags &= ~(WINEDDBLT_DDFX); 07061 } 07062 07063 #define COPY_COLORKEY_FX(type) \ 07064 do { \ 07065 const type *s; \ 07066 type *d = (type *)dbuf, *dx, tmp; \ 07067 for (y = sy = 0; y < dstheight; ++y, sy += yinc) \ 07068 { \ 07069 s = (const type *)(sbase + (sy >> 16) * src_map.row_pitch); \ 07070 dx = d; \ 07071 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \ 07072 { \ 07073 tmp = s[sx >> 16]; \ 07074 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \ 07075 && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \ 07076 { \ 07077 dx[0] = tmp; \ 07078 } \ 07079 dx = (type *)(((BYTE *)dx) + dstxinc); \ 07080 } \ 07081 d = (type *)(((BYTE *)d) + dstyinc); \ 07082 } \ 07083 } while(0) 07084 07085 switch (bpp) 07086 { 07087 case 1: 07088 COPY_COLORKEY_FX(BYTE); 07089 break; 07090 case 2: 07091 COPY_COLORKEY_FX(WORD); 07092 break; 07093 case 4: 07094 COPY_COLORKEY_FX(DWORD); 07095 break; 07096 case 3: 07097 { 07098 const BYTE *s; 07099 BYTE *d = dbuf, *dx; 07100 for (y = sy = 0; y < dstheight; ++y, sy += yinc) 07101 { 07102 sbuf = sbase + (sy >> 16) * src_map.row_pitch; 07103 dx = d; 07104 for (x = sx = 0; x < dstwidth; ++x, sx+= xinc) 07105 { 07106 DWORD pixel, dpixel = 0; 07107 s = sbuf + 3 * (sx>>16); 07108 pixel = s[0] | (s[1] << 8) | (s[2] << 16); 07109 dpixel = dx[0] | (dx[1] << 8 ) | (dx[2] << 16); 07110 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) 07111 && ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh)) 07112 { 07113 dx[0] = (pixel ) & 0xff; 07114 dx[1] = (pixel >> 8) & 0xff; 07115 dx[2] = (pixel >> 16) & 0xff; 07116 } 07117 dx += dstxinc; 07118 } 07119 d += dstyinc; 07120 } 07121 break; 07122 } 07123 default: 07124 FIXME("%s color-keyed blit not implemented for bpp %u!\n", 07125 (flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp * 8); 07126 hr = WINED3DERR_NOTAVAILABLE; 07127 goto error; 07128 #undef COPY_COLORKEY_FX 07129 } 07130 } 07131 } 07132 07133 error: 07134 if (flags && FIXME_ON(d3d_surface)) 07135 { 07136 FIXME("\tUnsupported flags: %#x.\n", flags); 07137 } 07138 07139 release: 07140 wined3d_surface_unmap(dst_surface); 07141 if (src_surface && src_surface != dst_surface) 07142 wined3d_surface_unmap(src_surface); 07143 /* Release the converted surface, if any. */ 07144 if (src_surface && src_surface != orig_src) 07145 wined3d_surface_decref(src_surface); 07146 07147 return hr; 07148 } 07149 07150 /* Do not call while under the GL lock. */ 07151 static HRESULT cpu_blit_color_fill(struct wined3d_device *device, struct wined3d_surface *dst_surface, 07152 const RECT *dst_rect, const struct wined3d_color *color) 07153 { 07154 static const RECT src_rect; 07155 WINEDDBLTFX BltFx; 07156 07157 memset(&BltFx, 0, sizeof(BltFx)); 07158 BltFx.dwSize = sizeof(BltFx); 07159 BltFx.u5.dwFillColor = wined3d_format_convert_from_float(dst_surface, color); 07160 return surface_cpu_blt(dst_surface, dst_rect, NULL, &src_rect, 07161 WINEDDBLT_COLORFILL, &BltFx, WINED3D_TEXF_POINT); 07162 } 07163 07164 /* Do not call while under the GL lock. */ 07165 static HRESULT cpu_blit_depth_fill(struct wined3d_device *device, 07166 struct wined3d_surface *surface, const RECT *rect, float depth) 07167 { 07168 FIXME("Depth filling not implemented by cpu_blit.\n"); 07169 return WINED3DERR_INVALIDCALL; 07170 } 07171 07172 const struct blit_shader cpu_blit = { 07173 cpu_blit_alloc, 07174 cpu_blit_free, 07175 cpu_blit_set, 07176 cpu_blit_unset, 07177 cpu_blit_supported, 07178 cpu_blit_color_fill, 07179 cpu_blit_depth_fill, 07180 }; 07181 07182 static HRESULT surface_init(struct wined3d_surface *surface, WINED3DSURFTYPE surface_type, UINT alignment, 07183 UINT width, UINT height, UINT level, enum wined3d_multisample_type multisample_type, 07184 UINT multisample_quality, struct wined3d_device *device, DWORD usage, enum wined3d_format_id format_id, 07185 enum wined3d_pool pool, DWORD flags, void *parent, const struct wined3d_parent_ops *parent_ops) 07186 { 07187 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; 07188 const struct wined3d_format *format = wined3d_get_format(gl_info, format_id); 07189 BOOL lockable = flags & WINED3D_SURFACE_MAPPABLE; 07190 unsigned int resource_size; 07191 HRESULT hr; 07192 07193 if (multisample_quality > 0) 07194 { 07195 FIXME("multisample_quality set to %u, substituting 0.\n", multisample_quality); 07196 multisample_quality = 0; 07197 } 07198 07199 /* Quick lockable sanity check. 07200 * TODO: remove this after surfaces, usage and lockability have been debugged properly 07201 * this function is too deep to need to care about things like this. 07202 * Levels need to be checked too, since they all affect what can be done. */ 07203 switch (pool) 07204 { 07205 case WINED3D_POOL_SCRATCH: 07206 if (!lockable) 07207 { 07208 FIXME("Called with a pool of SCRATCH and a lockable of FALSE " 07209 "which are mutually exclusive, setting lockable to TRUE.\n"); 07210 lockable = TRUE; 07211 } 07212 break; 07213 07214 case WINED3D_POOL_SYSTEM_MEM: 07215 if (!lockable) 07216 FIXME("Called with a pool of SYSTEMMEM and a lockable of FALSE, this is acceptable but unexpected.\n"); 07217 break; 07218 07219 case WINED3D_POOL_MANAGED: 07220 if (usage & WINED3DUSAGE_DYNAMIC) 07221 FIXME("Called with a pool of MANAGED and a usage of DYNAMIC which are mutually exclusive.\n"); 07222 break; 07223 07224 case WINED3D_POOL_DEFAULT: 07225 if (lockable && !(usage & (WINED3DUSAGE_DYNAMIC | WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL))) 07226 WARN("Creating a lockable surface with a POOL of DEFAULT, that doesn't specify DYNAMIC usage.\n"); 07227 break; 07228 07229 default: 07230 FIXME("Unknown pool %#x.\n", pool); 07231 break; 07232 }; 07233 07234 if (usage & WINED3DUSAGE_RENDERTARGET && pool != WINED3D_POOL_DEFAULT) 07235 FIXME("Trying to create a render target that isn't in the default pool.\n"); 07236 07237 /* FIXME: Check that the format is supported by the device. */ 07238 07239 resource_size = wined3d_format_calculate_size(format, alignment, width, height); 07240 if (!resource_size) 07241 return WINED3DERR_INVALIDCALL; 07242 07243 surface->surface_type = surface_type; 07244 07245 switch (surface_type) 07246 { 07247 case SURFACE_OPENGL: 07248 surface->surface_ops = &surface_ops; 07249 break; 07250 07251 case SURFACE_GDI: 07252 surface->surface_ops = &gdi_surface_ops; 07253 break; 07254 07255 default: 07256 ERR("Requested unknown surface implementation %#x.\n", surface_type); 07257 return WINED3DERR_INVALIDCALL; 07258 } 07259 07260 hr = resource_init(&surface->resource, device, WINED3D_RTYPE_SURFACE, format, 07261 multisample_type, multisample_quality, usage, pool, width, height, 1, 07262 resource_size, parent, parent_ops, &surface_resource_ops); 07263 if (FAILED(hr)) 07264 { 07265 WARN("Failed to initialize resource, returning %#x.\n", hr); 07266 return hr; 07267 } 07268 07269 /* "Standalone" surface. */ 07270 surface_set_container(surface, WINED3D_CONTAINER_NONE, NULL); 07271 07272 surface->texture_level = level; 07273 list_init(&surface->overlays); 07274 07275 /* Flags */ 07276 surface->flags = SFLAG_NORMCOORD; /* Default to normalized coords. */ 07277 if (flags & WINED3D_SURFACE_DISCARD) 07278 surface->flags |= SFLAG_DISCARD; 07279 if (flags & WINED3D_SURFACE_PIN_SYSMEM) 07280 surface->flags |= SFLAG_PIN_SYSMEM; 07281 if (lockable || format_id == WINED3DFMT_D16_LOCKABLE) 07282 surface->flags |= SFLAG_LOCKABLE; 07283 /* I'm not sure if this qualifies as a hack or as an optimization. It 07284 * seems reasonable to assume that lockable render targets will get 07285 * locked, so we might as well set SFLAG_DYNLOCK right at surface 07286 * creation. However, the other reason we want to do this is that several 07287 * ddraw applications access surface memory while the surface isn't 07288 * mapped. The SFLAG_DYNLOCK behaviour of keeping SYSMEM around for 07289 * future locks prevents these from crashing. */ 07290 if (lockable && (usage & WINED3DUSAGE_RENDERTARGET)) 07291 surface->flags |= SFLAG_DYNLOCK; 07292 07293 /* Mark the texture as dirty so that it gets loaded first time around. */ 07294 surface_add_dirty_rect(surface, NULL); 07295 list_init(&surface->renderbuffers); 07296 07297 TRACE("surface %p, memory %p, size %u\n", 07298 surface, surface->resource.allocatedMemory, surface->resource.size); 07299 07300 /* Call the private setup routine */ 07301 hr = surface->surface_ops->surface_private_setup(surface); 07302 if (FAILED(hr)) 07303 { 07304 ERR("Private setup failed, returning %#x\n", hr); 07305 surface_cleanup(surface); 07306 return hr; 07307 } 07308 07309 /* Similar to lockable rendertargets above, creating the DIB section 07310 * during surface initialization prevents the sysmem pointer from changing 07311 * after a wined3d_surface_getdc() call. */ 07312 if ((usage & WINED3DUSAGE_OWNDC) && !surface->hDC 07313 && SUCCEEDED(surface_create_dib_section(surface))) 07314 { 07315 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory); 07316 surface->resource.heapMemory = NULL; 07317 surface->resource.allocatedMemory = surface->dib.bitmap_data; 07318 } 07319 07320 return hr; 07321 } 07322 07323 HRESULT CDECL wined3d_surface_create(struct wined3d_device *device, UINT width, UINT height, 07324 enum wined3d_format_id format_id, UINT level, DWORD usage, enum wined3d_pool pool, 07325 enum wined3d_multisample_type multisample_type, DWORD multisample_quality, WINED3DSURFTYPE surface_type, 07326 DWORD flags, void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_surface **surface) 07327 { 07328 struct wined3d_surface *object; 07329 HRESULT hr; 07330 07331 TRACE("device %p, width %u, height %u, format %s, level %u\n", 07332 device, width, height, debug_d3dformat(format_id), level); 07333 TRACE("surface %p, usage %s (%#x), pool %s, multisample_type %#x, multisample_quality %u\n", 07334 surface, debug_d3dusage(usage), usage, debug_d3dpool(pool), multisample_type, multisample_quality); 07335 TRACE("surface_type %#x, flags %#x, parent %p, parent_ops %p.\n", surface_type, flags, parent, parent_ops); 07336 07337 if (surface_type == SURFACE_OPENGL && !device->adapter) 07338 { 07339 ERR("OpenGL surfaces are not available without OpenGL.\n"); 07340 return WINED3DERR_NOTAVAILABLE; 07341 } 07342 07343 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object)); 07344 if (!object) 07345 { 07346 ERR("Failed to allocate surface memory.\n"); 07347 return WINED3DERR_OUTOFVIDEOMEMORY; 07348 } 07349 07350 hr = surface_init(object, surface_type, device->surface_alignment, width, height, level, 07351 multisample_type, multisample_quality, device, usage, format_id, pool, flags, parent, parent_ops); 07352 if (FAILED(hr)) 07353 { 07354 WARN("Failed to initialize surface, returning %#x.\n", hr); 07355 HeapFree(GetProcessHeap(), 0, object); 07356 return hr; 07357 } 07358 07359 TRACE("Created surface %p.\n", object); 07360 *surface = object; 07361 07362 return hr; 07363 } Generated on Sat May 26 2012 04:20:39 for ReactOS by
1.7.6.1
|