1 /* 2 * IDirect3DSurface9 implementation 3 * 4 * Copyright 2002-2005 Jason Edmeades 5 * Raphael Junqueira 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 20 */ 21 22 #include "config.h" 23 #include "d3d9_private.h" 24 25 WINE_DEFAULT_DEBUG_CHANNEL(d3d9); 26 27 static inline struct d3d9_surface *impl_from_IDirect3DSurface9(IDirect3DSurface9 *iface) 28 { 29 return CONTAINING_RECORD(iface, struct d3d9_surface, IDirect3DSurface9_iface); 30 } 31 32 static HRESULT WINAPI d3d9_surface_QueryInterface(IDirect3DSurface9 *iface, REFIID riid, void **out) 33 { 34 TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out); 35 36 if (IsEqualGUID(riid, &IID_IDirect3DSurface9) 37 || IsEqualGUID(riid, &IID_IDirect3DResource9) 38 || IsEqualGUID(riid, &IID_IUnknown)) 39 { 40 IDirect3DSurface9_AddRef(iface); 41 *out = iface; 42 return S_OK; 43 } 44 45 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid)); 46 47 *out = NULL; 48 return E_NOINTERFACE; 49 } 50 51 static ULONG WINAPI d3d9_surface_AddRef(IDirect3DSurface9 *iface) 52 { 53 struct d3d9_surface *surface = impl_from_IDirect3DSurface9(iface); 54 ULONG refcount; 55 56 TRACE("iface %p.\n", iface); 57 58 if (surface->texture) 59 { 60 TRACE("Forwarding to %p.\n", surface->texture); 61 return IDirect3DBaseTexture9_AddRef(&surface->texture->IDirect3DBaseTexture9_iface); 62 } 63 64 refcount = InterlockedIncrement(&surface->resource.refcount); 65 TRACE("%p increasing refcount to %u.\n", iface, refcount); 66 67 if (refcount == 1) 68 { 69 if (surface->parent_device) 70 IDirect3DDevice9Ex_AddRef(surface->parent_device); 71 wined3d_mutex_lock(); 72 if (surface->wined3d_rtv) 73 wined3d_rendertarget_view_incref(surface->wined3d_rtv); 74 wined3d_texture_incref(surface->wined3d_texture); 75 wined3d_mutex_unlock(); 76 } 77 78 return refcount; 79 } 80 81 static ULONG WINAPI d3d9_surface_Release(IDirect3DSurface9 *iface) 82 { 83 struct d3d9_surface *surface = impl_from_IDirect3DSurface9(iface); 84 ULONG refcount; 85 86 TRACE("iface %p.\n", iface); 87 88 if (surface->texture) 89 { 90 TRACE("Forwarding to %p.\n", surface->texture); 91 return IDirect3DBaseTexture9_Release(&surface->texture->IDirect3DBaseTexture9_iface); 92 } 93 94 if (!surface->resource.refcount) 95 { 96 WARN("Surface does not have any references.\n"); 97 return 0; 98 } 99 100 refcount = InterlockedDecrement(&surface->resource.refcount); 101 TRACE("%p decreasing refcount to %u.\n", iface, refcount); 102 103 if (!refcount) 104 { 105 IDirect3DDevice9Ex *parent_device = surface->parent_device; 106 107 wined3d_mutex_lock(); 108 if (surface->wined3d_rtv) 109 wined3d_rendertarget_view_decref(surface->wined3d_rtv); 110 wined3d_texture_decref(surface->wined3d_texture); 111 wined3d_mutex_unlock(); 112 113 /* Release the device last, as it may cause the device to be destroyed. */ 114 if (parent_device) 115 IDirect3DDevice9Ex_Release(parent_device); 116 } 117 118 return refcount; 119 } 120 121 static HRESULT WINAPI d3d9_surface_GetDevice(IDirect3DSurface9 *iface, IDirect3DDevice9 **device) 122 { 123 struct d3d9_surface *surface = impl_from_IDirect3DSurface9(iface); 124 125 TRACE("iface %p, device %p.\n", iface, device); 126 127 if (surface->texture) 128 return IDirect3DBaseTexture9_GetDevice(&surface->texture->IDirect3DBaseTexture9_iface, device); 129 130 *device = (IDirect3DDevice9 *)surface->parent_device; 131 IDirect3DDevice9_AddRef(*device); 132 133 TRACE("Returning device %p.\n", *device); 134 135 return D3D_OK; 136 } 137 138 static HRESULT WINAPI d3d9_surface_SetPrivateData(IDirect3DSurface9 *iface, REFGUID guid, 139 const void *data, DWORD data_size, DWORD flags) 140 { 141 struct d3d9_surface *surface = impl_from_IDirect3DSurface9(iface); 142 TRACE("iface %p, guid %s, data %p, data_size %u, flags %#x.\n", 143 iface, debugstr_guid(guid), data, data_size, flags); 144 145 return d3d9_resource_set_private_data(&surface->resource, guid, data, data_size, flags); 146 } 147 148 static HRESULT WINAPI d3d9_surface_GetPrivateData(IDirect3DSurface9 *iface, REFGUID guid, 149 void *data, DWORD *data_size) 150 { 151 struct d3d9_surface *surface = impl_from_IDirect3DSurface9(iface); 152 TRACE("iface %p, guid %s, data %p, data_size %p.\n", 153 iface, debugstr_guid(guid), data, data_size); 154 155 return d3d9_resource_get_private_data(&surface->resource, guid, data, data_size); 156 } 157 158 static HRESULT WINAPI d3d9_surface_FreePrivateData(IDirect3DSurface9 *iface, REFGUID guid) 159 { 160 struct d3d9_surface *surface = impl_from_IDirect3DSurface9(iface); 161 TRACE("iface %p, guid %s.\n", iface, debugstr_guid(guid)); 162 163 return d3d9_resource_free_private_data(&surface->resource, guid); 164 } 165 166 static DWORD WINAPI d3d9_surface_SetPriority(IDirect3DSurface9 *iface, DWORD priority) 167 { 168 TRACE("iface %p, priority %u. Ignored on surfaces.\n", iface, priority); 169 return 0; 170 } 171 172 static DWORD WINAPI d3d9_surface_GetPriority(IDirect3DSurface9 *iface) 173 { 174 TRACE("iface %p. Ignored on surfaces.\n", iface); 175 return 0; 176 } 177 178 static void WINAPI d3d9_surface_PreLoad(IDirect3DSurface9 *iface) 179 { 180 struct d3d9_surface *surface = impl_from_IDirect3DSurface9(iface); 181 182 TRACE("iface %p.\n", iface); 183 184 wined3d_mutex_lock(); 185 wined3d_resource_preload(wined3d_texture_get_resource(surface->wined3d_texture)); 186 wined3d_mutex_unlock(); 187 } 188 189 static D3DRESOURCETYPE WINAPI d3d9_surface_GetType(IDirect3DSurface9 *iface) 190 { 191 TRACE("iface %p.\n", iface); 192 193 return D3DRTYPE_SURFACE; 194 } 195 196 static HRESULT WINAPI d3d9_surface_GetContainer(IDirect3DSurface9 *iface, REFIID riid, void **container) 197 { 198 struct d3d9_surface *surface = impl_from_IDirect3DSurface9(iface); 199 HRESULT hr; 200 201 TRACE("iface %p, riid %s, container %p.\n", iface, debugstr_guid(riid), container); 202 203 if (!surface->container) 204 return E_NOINTERFACE; 205 206 hr = IUnknown_QueryInterface(surface->container, riid, container); 207 208 TRACE("Returning %p.\n", *container); 209 210 return hr; 211 } 212 213 static HRESULT WINAPI d3d9_surface_GetDesc(IDirect3DSurface9 *iface, D3DSURFACE_DESC *desc) 214 { 215 struct d3d9_surface *surface = impl_from_IDirect3DSurface9(iface); 216 struct wined3d_sub_resource_desc wined3d_desc; 217 218 TRACE("iface %p, desc %p.\n", iface, desc); 219 220 wined3d_mutex_lock(); 221 wined3d_texture_get_sub_resource_desc(surface->wined3d_texture, surface->sub_resource_idx, &wined3d_desc); 222 wined3d_mutex_unlock(); 223 224 desc->Format = d3dformat_from_wined3dformat(wined3d_desc.format); 225 desc->Type = D3DRTYPE_SURFACE; 226 desc->Usage = d3dusage_from_wined3dusage(wined3d_desc.usage); 227 desc->Pool = d3dpool_from_wined3daccess(wined3d_desc.access, wined3d_desc.usage); 228 desc->MultiSampleType = wined3d_desc.multisample_type; 229 desc->MultiSampleQuality = wined3d_desc.multisample_quality; 230 desc->Width = wined3d_desc.width; 231 desc->Height = wined3d_desc.height; 232 233 return D3D_OK; 234 } 235 236 static HRESULT WINAPI d3d9_surface_LockRect(IDirect3DSurface9 *iface, 237 D3DLOCKED_RECT *locked_rect, const RECT *rect, DWORD flags) 238 { 239 struct d3d9_surface *surface = impl_from_IDirect3DSurface9(iface); 240 struct wined3d_box box; 241 struct wined3d_map_desc map_desc; 242 HRESULT hr; 243 244 TRACE("iface %p, locked_rect %p, rect %s, flags %#x.\n", 245 iface, locked_rect, wine_dbgstr_rect(rect), flags); 246 247 if (rect) 248 wined3d_box_set(&box, rect->left, rect->top, rect->right, rect->bottom, 0, 1); 249 250 wined3d_mutex_lock(); 251 hr = wined3d_resource_map(wined3d_texture_get_resource(surface->wined3d_texture), surface->sub_resource_idx, 252 &map_desc, rect ? &box : NULL, wined3dmapflags_from_d3dmapflags(flags)); 253 wined3d_mutex_unlock(); 254 255 if (SUCCEEDED(hr)) 256 { 257 locked_rect->Pitch = map_desc.row_pitch; 258 locked_rect->pBits = map_desc.data; 259 } 260 261 return hr; 262 } 263 264 static HRESULT WINAPI d3d9_surface_UnlockRect(IDirect3DSurface9 *iface) 265 { 266 struct d3d9_surface *surface = impl_from_IDirect3DSurface9(iface); 267 HRESULT hr; 268 269 TRACE("iface %p.\n", iface); 270 271 wined3d_mutex_lock(); 272 hr = wined3d_resource_unmap(wined3d_texture_get_resource(surface->wined3d_texture), surface->sub_resource_idx); 273 if (SUCCEEDED(hr) && surface->texture) 274 d3d9_texture_flag_auto_gen_mipmap(surface->texture); 275 wined3d_mutex_unlock(); 276 277 if (hr == WINEDDERR_NOTLOCKED) 278 { 279 D3DRESOURCETYPE type; 280 if (surface->texture) 281 type = IDirect3DBaseTexture9_GetType(&surface->texture->IDirect3DBaseTexture9_iface); 282 else 283 type = D3DRTYPE_SURFACE; 284 hr = type == D3DRTYPE_TEXTURE ? D3D_OK : D3DERR_INVALIDCALL; 285 } 286 return hr; 287 } 288 289 static HRESULT WINAPI d3d9_surface_GetDC(IDirect3DSurface9 *iface, HDC *dc) 290 { 291 struct d3d9_surface *surface = impl_from_IDirect3DSurface9(iface); 292 HRESULT hr; 293 294 TRACE("iface %p, dc %p.\n", iface, dc); 295 296 wined3d_mutex_lock(); 297 hr = wined3d_texture_get_dc(surface->wined3d_texture, surface->sub_resource_idx, dc); 298 wined3d_mutex_unlock(); 299 300 return hr; 301 } 302 303 static HRESULT WINAPI d3d9_surface_ReleaseDC(IDirect3DSurface9 *iface, HDC dc) 304 { 305 struct d3d9_surface *surface = impl_from_IDirect3DSurface9(iface); 306 HRESULT hr; 307 308 TRACE("iface %p, dc %p.\n", iface, dc); 309 310 wined3d_mutex_lock(); 311 hr = wined3d_texture_release_dc(surface->wined3d_texture, surface->sub_resource_idx, dc); 312 if (SUCCEEDED(hr) && surface->texture) 313 d3d9_texture_flag_auto_gen_mipmap(surface->texture); 314 wined3d_mutex_unlock(); 315 316 return hr; 317 } 318 319 static const struct IDirect3DSurface9Vtbl d3d9_surface_vtbl = 320 { 321 /* IUnknown */ 322 d3d9_surface_QueryInterface, 323 d3d9_surface_AddRef, 324 d3d9_surface_Release, 325 /* IDirect3DResource9 */ 326 d3d9_surface_GetDevice, 327 d3d9_surface_SetPrivateData, 328 d3d9_surface_GetPrivateData, 329 d3d9_surface_FreePrivateData, 330 d3d9_surface_SetPriority, 331 d3d9_surface_GetPriority, 332 d3d9_surface_PreLoad, 333 d3d9_surface_GetType, 334 /* IDirect3DSurface9 */ 335 d3d9_surface_GetContainer, 336 d3d9_surface_GetDesc, 337 d3d9_surface_LockRect, 338 d3d9_surface_UnlockRect, 339 d3d9_surface_GetDC, 340 d3d9_surface_ReleaseDC, 341 }; 342 343 static void STDMETHODCALLTYPE surface_wined3d_object_destroyed(void *parent) 344 { 345 struct d3d9_surface *surface = parent; 346 d3d9_resource_cleanup(&surface->resource); 347 heap_free(surface); 348 } 349 350 static const struct wined3d_parent_ops d3d9_surface_wined3d_parent_ops = 351 { 352 surface_wined3d_object_destroyed, 353 }; 354 355 void surface_init(struct d3d9_surface *surface, struct wined3d_texture *wined3d_texture, 356 unsigned int sub_resource_idx, const struct wined3d_parent_ops **parent_ops) 357 { 358 IDirect3DBaseTexture9 *texture; 359 360 surface->IDirect3DSurface9_iface.lpVtbl = &d3d9_surface_vtbl; 361 d3d9_resource_init(&surface->resource); 362 surface->resource.refcount = 0; 363 list_init(&surface->rtv_entry); 364 surface->container = wined3d_texture_get_parent(wined3d_texture); 365 surface->wined3d_texture = wined3d_texture; 366 surface->sub_resource_idx = sub_resource_idx; 367 368 if (surface->container && SUCCEEDED(IUnknown_QueryInterface(surface->container, 369 &IID_IDirect3DBaseTexture9, (void **)&texture))) 370 { 371 surface->texture = unsafe_impl_from_IDirect3DBaseTexture9(texture); 372 IDirect3DBaseTexture9_Release(texture); 373 } 374 375 *parent_ops = &d3d9_surface_wined3d_parent_ops; 376 } 377 378 static void STDMETHODCALLTYPE view_wined3d_object_destroyed(void *parent) 379 { 380 struct d3d9_surface *surface = parent; 381 382 /* If the surface reference count drops to zero, we release our reference 383 * to the view, but don't clear the pointer yet, in case e.g. a 384 * GetRenderTarget() call brings the surface back before the view is 385 * actually destroyed. When the view is destroyed, we need to clear the 386 * pointer, or a subsequent surface AddRef() would reference it again. 387 * 388 * This is safe because as long as the view still has a reference to the 389 * texture, the surface is also still alive, and we're called before the 390 * view releases that reference. */ 391 surface->wined3d_rtv = NULL; 392 list_remove(&surface->rtv_entry); 393 } 394 395 static const struct wined3d_parent_ops d3d9_view_wined3d_parent_ops = 396 { 397 view_wined3d_object_destroyed, 398 }; 399 400 struct d3d9_device *d3d9_surface_get_device(const struct d3d9_surface *surface) 401 { 402 IDirect3DDevice9Ex *device; 403 device = surface->texture ? surface->texture->parent_device : surface->parent_device; 404 return impl_from_IDirect3DDevice9Ex(device); 405 } 406 407 struct wined3d_rendertarget_view *d3d9_surface_acquire_rendertarget_view(struct d3d9_surface *surface) 408 { 409 HRESULT hr; 410 411 /* The surface reference count can be equal to 0 when this function is 412 * called. In order to properly manage the render target view reference 413 * count, we temporarily increment the surface reference count. */ 414 d3d9_surface_AddRef(&surface->IDirect3DSurface9_iface); 415 416 if (surface->wined3d_rtv) 417 return surface->wined3d_rtv; 418 419 if (FAILED(hr = wined3d_rendertarget_view_create_from_sub_resource(surface->wined3d_texture, 420 surface->sub_resource_idx, surface, &d3d9_view_wined3d_parent_ops, &surface->wined3d_rtv))) 421 { 422 ERR("Failed to create rendertarget view, hr %#x.\n", hr); 423 d3d9_surface_Release(&surface->IDirect3DSurface9_iface); 424 return NULL; 425 } 426 427 if (surface->texture) 428 list_add_head(&surface->texture->rtv_list, &surface->rtv_entry); 429 430 return surface->wined3d_rtv; 431 } 432 433 void d3d9_surface_release_rendertarget_view(struct d3d9_surface *surface, 434 struct wined3d_rendertarget_view *rtv) 435 { 436 if (rtv) 437 d3d9_surface_Release(&surface->IDirect3DSurface9_iface); 438 } 439 440 struct d3d9_surface *unsafe_impl_from_IDirect3DSurface9(IDirect3DSurface9 *iface) 441 { 442 if (!iface) 443 return NULL; 444 assert(iface->lpVtbl == &d3d9_surface_vtbl); 445 446 return impl_from_IDirect3DSurface9(iface); 447 } 448