1 /* 2 * IDirect3DSurface8 implementation 3 * 4 * Copyright 2005 Oliver Stieber 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #include "config.h" 22 #include "d3d8_private.h" 23 24 WINE_DEFAULT_DEBUG_CHANNEL(d3d8); 25 26 static inline struct d3d8_surface *impl_from_IDirect3DSurface8(IDirect3DSurface8 *iface) 27 { 28 return CONTAINING_RECORD(iface, struct d3d8_surface, IDirect3DSurface8_iface); 29 } 30 31 static HRESULT WINAPI d3d8_surface_QueryInterface(IDirect3DSurface8 *iface, REFIID riid, void **out) 32 { 33 TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out); 34 35 if (IsEqualGUID(riid, &IID_IDirect3DSurface8) 36 || IsEqualGUID(riid, &IID_IDirect3DResource8) 37 || IsEqualGUID(riid, &IID_IUnknown)) 38 { 39 IDirect3DSurface8_AddRef(iface); 40 *out = iface; 41 return S_OK; 42 } 43 44 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid)); 45 46 *out = NULL; 47 return E_NOINTERFACE; 48 } 49 50 static ULONG WINAPI d3d8_surface_AddRef(IDirect3DSurface8 *iface) 51 { 52 struct d3d8_surface *surface = impl_from_IDirect3DSurface8(iface); 53 ULONG refcount; 54 55 TRACE("iface %p.\n", iface); 56 57 if (surface->texture) 58 { 59 TRACE("Forwarding to %p.\n", surface->texture); 60 return IDirect3DBaseTexture8_AddRef(&surface->texture->IDirect3DBaseTexture8_iface); 61 } 62 63 refcount = InterlockedIncrement(&surface->resource.refcount); 64 TRACE("%p increasing refcount to %u.\n", iface, refcount); 65 66 if (refcount == 1) 67 { 68 if (surface->parent_device) 69 IDirect3DDevice8_AddRef(surface->parent_device); 70 wined3d_mutex_lock(); 71 if (surface->wined3d_rtv) 72 wined3d_rendertarget_view_incref(surface->wined3d_rtv); 73 wined3d_texture_incref(surface->wined3d_texture); 74 wined3d_mutex_unlock(); 75 } 76 77 return refcount; 78 } 79 80 static ULONG WINAPI d3d8_surface_Release(IDirect3DSurface8 *iface) 81 { 82 struct d3d8_surface *surface = impl_from_IDirect3DSurface8(iface); 83 ULONG refcount; 84 85 TRACE("iface %p.\n", iface); 86 87 if (surface->texture) 88 { 89 TRACE("Forwarding to %p.\n", surface->texture); 90 return IDirect3DBaseTexture8_Release(&surface->texture->IDirect3DBaseTexture8_iface); 91 } 92 93 if (!surface->resource.refcount) 94 { 95 WARN("Surface does not have any references.\n"); 96 return 0; 97 } 98 99 refcount = InterlockedDecrement(&surface->resource.refcount); 100 TRACE("%p decreasing refcount to %u.\n", iface, refcount); 101 102 if (!refcount) 103 { 104 IDirect3DDevice8 *parent_device = surface->parent_device; 105 106 wined3d_mutex_lock(); 107 if (surface->wined3d_rtv) 108 wined3d_rendertarget_view_decref(surface->wined3d_rtv); 109 wined3d_texture_decref(surface->wined3d_texture); 110 wined3d_mutex_unlock(); 111 112 if (parent_device) 113 IDirect3DDevice8_Release(parent_device); 114 } 115 116 return refcount; 117 } 118 119 static HRESULT WINAPI d3d8_surface_GetDevice(IDirect3DSurface8 *iface, IDirect3DDevice8 **device) 120 { 121 struct d3d8_surface *surface = impl_from_IDirect3DSurface8(iface); 122 123 TRACE("iface %p, device %p.\n", iface, device); 124 125 if (surface->texture) 126 return IDirect3DBaseTexture8_GetDevice(&surface->texture->IDirect3DBaseTexture8_iface, device); 127 128 *device = surface->parent_device; 129 IDirect3DDevice8_AddRef(*device); 130 131 TRACE("Returning device %p.\n", *device); 132 133 return D3D_OK; 134 } 135 136 static HRESULT WINAPI d3d8_surface_SetPrivateData(IDirect3DSurface8 *iface, REFGUID guid, 137 const void *data, DWORD data_size, DWORD flags) 138 { 139 struct d3d8_surface *surface = impl_from_IDirect3DSurface8(iface); 140 TRACE("iface %p, guid %s, data %p, data_size %u, flags %#x.\n", 141 iface, debugstr_guid(guid), data, data_size, flags); 142 143 return d3d8_resource_set_private_data(&surface->resource, guid, data, data_size, flags); 144 } 145 146 static HRESULT WINAPI d3d8_surface_GetPrivateData(IDirect3DSurface8 *iface, REFGUID guid, 147 void *data, DWORD *data_size) 148 { 149 struct d3d8_surface *surface = impl_from_IDirect3DSurface8(iface); 150 TRACE("iface %p, guid %s, data %p, data_size %p.\n", 151 iface, debugstr_guid(guid), data, data_size); 152 153 return d3d8_resource_get_private_data(&surface->resource, guid, data, data_size); 154 } 155 156 static HRESULT WINAPI d3d8_surface_FreePrivateData(IDirect3DSurface8 *iface, REFGUID guid) 157 { 158 struct d3d8_surface *surface = impl_from_IDirect3DSurface8(iface); 159 TRACE("iface %p, guid %s.\n", iface, debugstr_guid(guid)); 160 161 return d3d8_resource_free_private_data(&surface->resource, guid); 162 } 163 164 static HRESULT WINAPI d3d8_surface_GetContainer(IDirect3DSurface8 *iface, REFIID riid, void **container) 165 { 166 struct d3d8_surface *surface = impl_from_IDirect3DSurface8(iface); 167 HRESULT hr; 168 169 TRACE("iface %p, riid %s, container %p.\n", iface, debugstr_guid(riid), container); 170 171 if (!surface->container) 172 return E_NOINTERFACE; 173 174 hr = IUnknown_QueryInterface(surface->container, riid, container); 175 176 TRACE("Returning %p.\n", *container); 177 178 return hr; 179 } 180 181 static HRESULT WINAPI d3d8_surface_GetDesc(IDirect3DSurface8 *iface, D3DSURFACE_DESC *desc) 182 { 183 struct d3d8_surface *surface = impl_from_IDirect3DSurface8(iface); 184 struct wined3d_sub_resource_desc wined3d_desc; 185 186 TRACE("iface %p, desc %p.\n", iface, desc); 187 188 wined3d_mutex_lock(); 189 wined3d_texture_get_sub_resource_desc(surface->wined3d_texture, surface->sub_resource_idx, &wined3d_desc); 190 wined3d_mutex_unlock(); 191 192 desc->Format = d3dformat_from_wined3dformat(wined3d_desc.format); 193 desc->Type = D3DRTYPE_SURFACE; 194 desc->Usage = d3dusage_from_wined3dusage(wined3d_desc.usage); 195 desc->Pool = d3dpool_from_wined3daccess(wined3d_desc.access, wined3d_desc.usage); 196 desc->Size = wined3d_desc.size; 197 desc->MultiSampleType = wined3d_desc.multisample_type; 198 desc->Width = wined3d_desc.width; 199 desc->Height = wined3d_desc.height; 200 201 return D3D_OK; 202 } 203 204 static HRESULT WINAPI d3d8_surface_LockRect(IDirect3DSurface8 *iface, 205 D3DLOCKED_RECT *locked_rect, const RECT *rect, DWORD flags) 206 { 207 struct d3d8_surface *surface = impl_from_IDirect3DSurface8(iface); 208 struct wined3d_box box; 209 struct wined3d_map_desc map_desc; 210 HRESULT hr; 211 D3DRESOURCETYPE type; 212 213 TRACE("iface %p, locked_rect %p, rect %s, flags %#x.\n", 214 iface, locked_rect, wine_dbgstr_rect(rect), flags); 215 216 wined3d_mutex_lock(); 217 218 if (surface->texture) 219 type = IDirect3DBaseTexture8_GetType(&surface->texture->IDirect3DBaseTexture8_iface); 220 else 221 type = D3DRTYPE_SURFACE; 222 223 if (rect) 224 { 225 D3DSURFACE_DESC desc; 226 IDirect3DSurface8_GetDesc(iface, &desc); 227 228 if (type != D3DRTYPE_TEXTURE 229 && ((rect->left < 0) 230 || (rect->top < 0) 231 || (rect->left >= rect->right) 232 || (rect->top >= rect->bottom) 233 || (rect->right > desc.Width) 234 || (rect->bottom > desc.Height))) 235 { 236 WARN("Trying to lock an invalid rectangle, returning D3DERR_INVALIDCALL\n"); 237 wined3d_mutex_unlock(); 238 239 locked_rect->Pitch = 0; 240 locked_rect->pBits = NULL; 241 return D3DERR_INVALIDCALL; 242 } 243 wined3d_box_set(&box, rect->left, rect->top, rect->right, rect->bottom, 0, 1); 244 } 245 246 hr = wined3d_resource_map(wined3d_texture_get_resource(surface->wined3d_texture), surface->sub_resource_idx, 247 &map_desc, rect ? &box : NULL, wined3dmapflags_from_d3dmapflags(flags)); 248 wined3d_mutex_unlock(); 249 250 if (SUCCEEDED(hr)) 251 { 252 locked_rect->Pitch = map_desc.row_pitch; 253 locked_rect->pBits = map_desc.data; 254 } 255 else if (type != D3DRTYPE_TEXTURE) 256 { 257 locked_rect->Pitch = 0; 258 locked_rect->pBits = NULL; 259 } 260 261 return hr; 262 } 263 264 static HRESULT WINAPI d3d8_surface_UnlockRect(IDirect3DSurface8 *iface) 265 { 266 struct d3d8_surface *surface = impl_from_IDirect3DSurface8(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 wined3d_mutex_unlock(); 274 275 if (hr == WINEDDERR_NOTLOCKED) 276 { 277 D3DRESOURCETYPE type; 278 if (surface->texture) 279 type = IDirect3DBaseTexture8_GetType(&surface->texture->IDirect3DBaseTexture8_iface); 280 else 281 type = D3DRTYPE_SURFACE; 282 hr = type == D3DRTYPE_TEXTURE ? D3D_OK : D3DERR_INVALIDCALL; 283 } 284 return hr; 285 } 286 287 static const IDirect3DSurface8Vtbl d3d8_surface_vtbl = 288 { 289 /* IUnknown */ 290 d3d8_surface_QueryInterface, 291 d3d8_surface_AddRef, 292 d3d8_surface_Release, 293 /* IDirect3DResource8 */ 294 d3d8_surface_GetDevice, 295 d3d8_surface_SetPrivateData, 296 d3d8_surface_GetPrivateData, 297 d3d8_surface_FreePrivateData, 298 /* IDirect3DSurface8 */ 299 d3d8_surface_GetContainer, 300 d3d8_surface_GetDesc, 301 d3d8_surface_LockRect, 302 d3d8_surface_UnlockRect, 303 }; 304 305 static void STDMETHODCALLTYPE surface_wined3d_object_destroyed(void *parent) 306 { 307 struct d3d8_surface *surface = parent; 308 d3d8_resource_cleanup(&surface->resource); 309 heap_free(surface); 310 } 311 312 static const struct wined3d_parent_ops d3d8_surface_wined3d_parent_ops = 313 { 314 surface_wined3d_object_destroyed, 315 }; 316 317 void surface_init(struct d3d8_surface *surface, struct wined3d_texture *wined3d_texture, unsigned int sub_resource_idx, 318 const struct wined3d_parent_ops **parent_ops) 319 { 320 IDirect3DBaseTexture8 *texture; 321 322 surface->IDirect3DSurface8_iface.lpVtbl = &d3d8_surface_vtbl; 323 d3d8_resource_init(&surface->resource); 324 surface->resource.refcount = 0; 325 list_init(&surface->rtv_entry); 326 surface->container = wined3d_texture_get_parent(wined3d_texture); 327 surface->wined3d_texture = wined3d_texture; 328 surface->sub_resource_idx = sub_resource_idx; 329 330 if (surface->container && SUCCEEDED(IUnknown_QueryInterface(surface->container, 331 &IID_IDirect3DBaseTexture8, (void **)&texture))) 332 { 333 surface->texture = unsafe_impl_from_IDirect3DBaseTexture8(texture); 334 IDirect3DBaseTexture8_Release(texture); 335 } 336 337 *parent_ops = &d3d8_surface_wined3d_parent_ops; 338 } 339 340 static void STDMETHODCALLTYPE view_wined3d_object_destroyed(void *parent) 341 { 342 struct d3d8_surface *surface = parent; 343 344 /* If the surface reference count drops to zero, we release our reference 345 * to the view, but don't clear the pointer yet, in case e.g. a 346 * GetRenderTarget() call brings the surface back before the view is 347 * actually destroyed. When the view is destroyed, we need to clear the 348 * pointer, or a subsequent surface AddRef() would reference it again. 349 * 350 * This is safe because as long as the view still has a reference to the 351 * texture, the surface is also still alive, and we're called before the 352 * view releases that reference. */ 353 surface->wined3d_rtv = NULL; 354 list_remove(&surface->rtv_entry); 355 } 356 357 static const struct wined3d_parent_ops d3d8_view_wined3d_parent_ops = 358 { 359 view_wined3d_object_destroyed, 360 }; 361 362 struct d3d8_device *d3d8_surface_get_device(const struct d3d8_surface *surface) 363 { 364 IDirect3DDevice8 *device; 365 device = surface->texture ? surface->texture->parent_device : surface->parent_device; 366 return impl_from_IDirect3DDevice8(device); 367 } 368 369 struct wined3d_rendertarget_view *d3d8_surface_acquire_rendertarget_view(struct d3d8_surface *surface) 370 { 371 HRESULT hr; 372 373 /* The surface reference count can be equal to 0 when this function is 374 * called. In order to properly manage the render target view reference 375 * count, we temporarily increment the surface reference count. */ 376 d3d8_surface_AddRef(&surface->IDirect3DSurface8_iface); 377 378 if (surface->wined3d_rtv) 379 return surface->wined3d_rtv; 380 381 if (FAILED(hr = wined3d_rendertarget_view_create_from_sub_resource(surface->wined3d_texture, 382 surface->sub_resource_idx, surface, &d3d8_view_wined3d_parent_ops, &surface->wined3d_rtv))) 383 { 384 ERR("Failed to create rendertarget view, hr %#x.\n", hr); 385 d3d8_surface_Release(&surface->IDirect3DSurface8_iface); 386 return NULL; 387 } 388 389 if (surface->texture) 390 list_add_head(&surface->texture->rtv_list, &surface->rtv_entry); 391 392 return surface->wined3d_rtv; 393 } 394 395 void d3d8_surface_release_rendertarget_view(struct d3d8_surface *surface, 396 struct wined3d_rendertarget_view *rtv) 397 { 398 if (rtv) 399 d3d8_surface_Release(&surface->IDirect3DSurface8_iface); 400 } 401 402 struct d3d8_surface *unsafe_impl_from_IDirect3DSurface8(IDirect3DSurface8 *iface) 403 { 404 if (!iface) 405 return NULL; 406 assert(iface->lpVtbl == &d3d8_surface_vtbl); 407 408 return impl_from_IDirect3DSurface8(iface); 409 } 410