HRESULT WINAPI NineTexture9_AddDirtyRect( struct NineTexture9 *This, const RECT *pDirtyRect ) { DBG("This=%p pDirtyRect=%p[(%u,%u)-(%u,%u)]\n", This, pDirtyRect, pDirtyRect ? pDirtyRect->left : 0, pDirtyRect ? pDirtyRect->top : 0, pDirtyRect ? pDirtyRect->right : 0, pDirtyRect ? pDirtyRect->bottom : 0); /* Tracking dirty regions on DEFAULT or SYSTEMMEM resources is pointless, * because we always write to the final storage. Just marked it dirty in * case we need to generate mip maps. */ if (This->base.base.pool != D3DPOOL_MANAGED) { if (This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP) This->base.dirty_mip = TRUE; return D3D_OK; } This->base.managed.dirty = TRUE; BASETEX_REGISTER_UPDATE(&This->base); if (!pDirtyRect) { u_box_origin_2d(This->base.base.info.width0, This->base.base.info.height0, &This->dirty_rect); } else { struct pipe_box box; rect_to_pipe_box_clamp(&box, pDirtyRect); u_box_union_2d(&This->dirty_rect, &This->dirty_rect, &box); (void) u_box_clip_2d(&This->dirty_rect, &This->dirty_rect, This->base.base.info.width0, This->base.base.info.height0); } return D3D_OK; }
HRESULT NINE_WINAPI NineCubeTexture9_AddDirtyRect( struct NineCubeTexture9 *This, D3DCUBEMAP_FACES FaceType, const RECT *pDirtyRect ) { DBG("This=%p FaceType=%d pDirtyRect=%p\n", This, FaceType, pDirtyRect); user_assert(FaceType < 6, D3DERR_INVALIDCALL); if (This->base.base.pool != D3DPOOL_MANAGED) { if (This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP) { This->base.dirty_mip = TRUE; BASETEX_REGISTER_UPDATE(&This->base); } return D3D_OK; } if (This->base.base.pool == D3DPOOL_MANAGED) { This->base.managed.dirty = TRUE; BASETEX_REGISTER_UPDATE(&This->base); } if (!pDirtyRect) { u_box_origin_2d(This->base.base.info.width0, This->base.base.info.height0, &This->dirty_rect[FaceType]); } else { struct pipe_box box; rect_to_pipe_box_clamp(&box, pDirtyRect); u_box_union_2d(&This->dirty_rect[FaceType], &This->dirty_rect[FaceType], &box); (void) u_box_clip_2d(&This->dirty_rect[FaceType], &This->dirty_rect[FaceType], This->base.base.info.width0, This->base.base.info.height0); } return D3D_OK; }
HRESULT WINAPI NineVolume9_LockBox( struct NineVolume9 *This, D3DLOCKED_BOX *pLockedVolume, const D3DBOX *pBox, DWORD Flags ) { struct pipe_resource *resource = This->resource; struct pipe_box box; unsigned usage; DBG("This=%p(%p) pLockedVolume=%p pBox=%p[%u..%u,%u..%u,%u..%u] Flags=%s\n", This, This->base.container, pLockedVolume, pBox, pBox ? pBox->Left : 0, pBox ? pBox->Right : 0, pBox ? pBox->Top : 0, pBox ? pBox->Bottom : 0, pBox ? pBox->Front : 0, pBox ? pBox->Back : 0, nine_D3DLOCK_to_str(Flags)); user_assert(This->desc.Pool != D3DPOOL_DEFAULT || (This->desc.Usage & D3DUSAGE_DYNAMIC), D3DERR_INVALIDCALL); user_assert(!((Flags & D3DLOCK_DISCARD) && (Flags & D3DLOCK_READONLY)), D3DERR_INVALIDCALL); user_assert(This->lock_count == 0, D3DERR_INVALIDCALL); user_assert(pLockedVolume, E_POINTER); if (pBox && This->desc.Pool == D3DPOOL_DEFAULT && util_format_is_compressed(This->info.format)) { const unsigned w = util_format_get_blockwidth(This->info.format); const unsigned h = util_format_get_blockheight(This->info.format); user_assert(!(pBox->Left % w) && !(pBox->Right % w) && !(pBox->Top % h) && !(pBox->Bottom % h), D3DERR_INVALIDCALL); } if (Flags & D3DLOCK_DISCARD) { usage = PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD_RANGE; } else { usage = (Flags & D3DLOCK_READONLY) ? PIPE_TRANSFER_READ : PIPE_TRANSFER_READ_WRITE; } if (Flags & D3DLOCK_DONOTWAIT) usage |= PIPE_TRANSFER_DONTBLOCK; if (pBox) { d3dbox_to_pipe_box(&box, pBox); if (u_box_clip_2d(&box, &box, This->desc.Width, This->desc.Height) < 0) { DBG("Locked volume intersection empty.\n"); return D3DERR_INVALIDCALL; } } else { u_box_3d(0, 0, 0, This->desc.Width, This->desc.Height, This->desc.Depth, &box); } if (This->data) { pLockedVolume->RowPitch = This->stride; pLockedVolume->SlicePitch = This->layer_stride; pLockedVolume->pBits = NineVolume9_GetSystemMemPointer(This, box.x, box.y, box.z); } else { pLockedVolume->pBits = This->pipe->transfer_map(This->pipe, resource, This->level, usage, &box, &This->transfer); if (!This->transfer) { if (Flags & D3DLOCK_DONOTWAIT) return D3DERR_WASSTILLDRAWING; return D3DERR_DRIVERINTERNALERROR; } pLockedVolume->RowPitch = This->transfer->stride; pLockedVolume->SlicePitch = This->transfer->layer_stride; } if (!(Flags & (D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_READONLY))) { NineVolume9_MarkContainerDirty(This); if (This->desc.Pool == D3DPOOL_MANAGED) NineVolume9_AddDirtyRegion(This, &box); } ++This->lock_count; return D3D_OK; }
HRESULT WINAPI NineSurface9_LockRect( struct NineSurface9 *This, D3DLOCKED_RECT *pLockedRect, const RECT *pRect, DWORD Flags ) { struct pipe_resource *resource = This->base.resource; struct pipe_box box; unsigned usage; DBG("This=%p pLockedRect=%p pRect=%p[%u..%u,%u..%u] Flags=%s\n", This, pLockedRect, pRect, pRect ? pRect->left : 0, pRect ? pRect->right : 0, pRect ? pRect->top : 0, pRect ? pRect->bottom : 0, nine_D3DLOCK_to_str(Flags)); NineSurface9_Dump(This); #ifdef NINE_STRICT user_assert(This->base.pool != D3DPOOL_DEFAULT || (resource && (resource->flags & NINE_RESOURCE_FLAG_LOCKABLE)), D3DERR_INVALIDCALL); #endif user_assert(!(Flags & ~(D3DLOCK_DISCARD | D3DLOCK_DONOTWAIT | D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_NOOVERWRITE | D3DLOCK_NOSYSLOCK | /* ignored */ D3DLOCK_READONLY)), D3DERR_INVALIDCALL); user_assert(!((Flags & D3DLOCK_DISCARD) && (Flags & D3DLOCK_READONLY)), D3DERR_INVALIDCALL); /* check if it's already locked */ user_assert(This->lock_count == 0, D3DERR_INVALIDCALL); user_assert(pLockedRect, E_POINTER); user_assert(This->desc.MultiSampleType == D3DMULTISAMPLE_NONE, D3DERR_INVALIDCALL); if (pRect && This->base.pool == D3DPOOL_DEFAULT && util_format_is_compressed(This->base.info.format)) { const unsigned w = util_format_get_blockwidth(This->base.info.format); const unsigned h = util_format_get_blockheight(This->base.info.format); user_assert(!(pRect->left % w) && !(pRect->right % w) && !(pRect->top % h) && !(pRect->bottom % h), D3DERR_INVALIDCALL); } if (Flags & D3DLOCK_DISCARD) { usage = PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD_RANGE; } else { usage = (Flags & D3DLOCK_READONLY) ? PIPE_TRANSFER_READ : PIPE_TRANSFER_READ_WRITE; } if (Flags & D3DLOCK_DONOTWAIT) usage |= PIPE_TRANSFER_DONTBLOCK; if (pRect) { rect_to_pipe_box(&box, pRect); if (u_box_clip_2d(&box, &box, This->desc.Width, This->desc.Height) < 0) { DBG("pRect clipped by Width=%u Height=%u\n", This->desc.Width, This->desc.Height); return D3DERR_INVALIDCALL; } } else { u_box_origin_2d(This->desc.Width, This->desc.Height, &box); } user_warn(This->desc.Format == D3DFMT_NULL); if (This->data) { DBG("returning system memory\n"); /* ATI1 and ATI2 need special handling, because of d3d9 bug. * We must advertise to the application as if it is uncompressed * and bpp 8, and the app has a workaround to work with the fact * that it is actually compressed. */ if (is_ATI1_ATI2(This->base.info.format)) { pLockedRect->Pitch = This->desc.Height; pLockedRect->pBits = This->data + box.y * This->desc.Height + box.x; } else { pLockedRect->Pitch = This->stride; pLockedRect->pBits = NineSurface9_GetSystemMemPointer(This, box.x, box.y); } } else { DBG("mapping pipe_resource %p (level=%u usage=%x)\n", resource, This->level, usage); pLockedRect->pBits = This->pipe->transfer_map(This->pipe, resource, This->level, usage, &box, &This->transfer); if (!This->transfer) { DBG("transfer_map failed\n"); if (Flags & D3DLOCK_DONOTWAIT) return D3DERR_WASSTILLDRAWING; return D3DERR_INVALIDCALL; } pLockedRect->Pitch = This->transfer->stride; } if (!(Flags & (D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_READONLY))) { NineSurface9_MarkContainerDirty(This); NineSurface9_AddDirtyRect(This, &box); } ++This->lock_count; return D3D_OK; }
HRESULT NINE_WINAPI NineVolume9_LockBox( struct NineVolume9 *This, D3DLOCKED_BOX *pLockedVolume, const D3DBOX *pBox, DWORD Flags ) { struct pipe_resource *resource = This->resource; struct pipe_box box; unsigned usage; DBG("This=%p(%p) pLockedVolume=%p pBox=%p[%u..%u,%u..%u,%u..%u] Flags=%s\n", This, This->base.container, pLockedVolume, pBox, pBox ? pBox->Left : 0, pBox ? pBox->Right : 0, pBox ? pBox->Top : 0, pBox ? pBox->Bottom : 0, pBox ? pBox->Front : 0, pBox ? pBox->Back : 0, nine_D3DLOCK_to_str(Flags)); /* check if it's already locked */ user_assert(This->lock_count == 0, D3DERR_INVALIDCALL); /* set pBits to NULL after lock_count check */ user_assert(pLockedVolume, E_POINTER); pLockedVolume->pBits = NULL; user_assert(This->desc.Pool != D3DPOOL_DEFAULT || (This->desc.Usage & D3DUSAGE_DYNAMIC), D3DERR_INVALIDCALL); user_assert(!((Flags & D3DLOCK_DISCARD) && (Flags & D3DLOCK_READONLY)), D3DERR_INVALIDCALL); if (pBox && compressed_format (This->desc.Format)) { /* For volume all pools are checked */ const unsigned w = util_format_get_blockwidth(This->info.format); const unsigned h = util_format_get_blockheight(This->info.format); user_assert((pBox->Left == 0 && pBox->Right == This->desc.Width && pBox->Top == 0 && pBox->Bottom == This->desc.Height) || (!(pBox->Left % w) && !(pBox->Right % w) && !(pBox->Top % h) && !(pBox->Bottom % h)), D3DERR_INVALIDCALL); } if (Flags & D3DLOCK_DISCARD) { usage = PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD_RANGE; } else { usage = (Flags & D3DLOCK_READONLY) ? PIPE_TRANSFER_READ : PIPE_TRANSFER_READ_WRITE; } if (Flags & D3DLOCK_DONOTWAIT) usage |= PIPE_TRANSFER_DONTBLOCK; if (pBox) { user_assert(pBox->Right > pBox->Left, D3DERR_INVALIDCALL); user_assert(pBox->Bottom > pBox->Top, D3DERR_INVALIDCALL); user_assert(pBox->Back > pBox->Front, D3DERR_INVALIDCALL); user_assert(pBox->Right <= This->desc.Width, D3DERR_INVALIDCALL); user_assert(pBox->Bottom <= This->desc.Height, D3DERR_INVALIDCALL); user_assert(pBox->Back <= This->desc.Depth, D3DERR_INVALIDCALL); d3dbox_to_pipe_box(&box, pBox); if (u_box_clip_2d(&box, &box, This->desc.Width, This->desc.Height) < 0) { DBG("Locked volume intersection empty.\n"); return D3DERR_INVALIDCALL; } } else { u_box_3d(0, 0, 0, This->desc.Width, This->desc.Height, This->desc.Depth, &box); } if (This->data_conversion) { /* For now we only have uncompressed formats here */ pLockedVolume->RowPitch = This->stride_conversion; pLockedVolume->SlicePitch = This->layer_stride_conversion; pLockedVolume->pBits = This->data_conversion + box.z * This->layer_stride_conversion + box.y * This->stride_conversion + util_format_get_stride(This->format_conversion, box.x); } else if (This->data) { pLockedVolume->RowPitch = This->stride; pLockedVolume->SlicePitch = This->layer_stride; pLockedVolume->pBits = NineVolume9_GetSystemMemPointer(This, box.x, box.y, box.z); } else { pLockedVolume->pBits = This->pipe->transfer_map(This->pipe, resource, This->level, usage, &box, &This->transfer); if (!This->transfer) { if (Flags & D3DLOCK_DONOTWAIT) return D3DERR_WASSTILLDRAWING; return D3DERR_DRIVERINTERNALERROR; } pLockedVolume->RowPitch = This->transfer->stride; pLockedVolume->SlicePitch = This->transfer->layer_stride; } if (!(Flags & (D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_READONLY))) { NineVolume9_MarkContainerDirty(This); NineVolume9_AddDirtyRegion(This, &box); } ++This->lock_count; return D3D_OK; }
static INLINE HRESULT present( struct NineSwapChain9 *This, const RECT *pSourceRect, const RECT *pDestRect, HWND hDestWindowOverride, const RGNDATA *pDirtyRegion, DWORD dwFlags ) { struct NineDevice9 *device = This->base.device; struct pipe_resource *resource; HRESULT hr; RGNDATA *rgndata; RECT rect; struct pipe_blit_info blit; /* get a real backbuffer handle from the windowing system */ hr = This->actx->resource_from_present(This->actx, This->screen, This->present, hDestWindowOverride, pDestRect, &rect, &rgndata, &resource); if (FAILED(hr)) { return hr; } else if (hr == D3DOK_WINDOW_OCCLUDED) { /* if we present, nothing will show, so don't present */ return D3D_OK; } DBG(">>>\npresent: This=%p pSourceRect=%p pDestRect=%p " "pDirtyRegion=%p rgndata=%p\n", This, pSourceRect, pDestRect, pDirtyRegion, rgndata); if (pSourceRect) DBG("pSourceRect = (%u..%u)x(%u..%u)\n", pSourceRect->left, pSourceRect->right, pSourceRect->top, pSourceRect->bottom); if (pDestRect) DBG("pDestRect = (%u..%u)x(%u..%u)\n", pDestRect->left, pDestRect->right, pDestRect->top, pDestRect->bottom); if (rgndata) { /* TODO */ blit.dst.resource = NULL; } else { struct pipe_surface *suf = NineSurface9_GetSurface(This->buffers[0], 0); blit.dst.resource = resource; blit.dst.level = 0; blit.dst.format = resource->format; blit.dst.box.z = 0; blit.dst.box.depth = 1; if (pDestRect) { rect_to_pipe_box_xy_only(&blit.dst.box, pDestRect); blit.dst.box.x += rect.left; blit.dst.box.y += rect.top; if (u_box_clip_2d(&blit.dst.box, &blit.dst.box, rect.right, rect.bottom) > 0) { DBG("Dest region clipped.\n"); return D3D_OK; } } else { rect_to_pipe_box_xy_only(&blit.dst.box, &rect); } blit.src.resource = suf->texture; blit.src.level = This->buffers[0]->level; blit.src.format = blit.src.resource->format; blit.src.box.z = 0; blit.src.box.depth = 1; if (pSourceRect) { rect_to_pipe_box_xy_only(&blit.src.box, pSourceRect); u_box_clip_2d(&blit.src.box, &blit.src.box, suf->width, suf->height); } else { blit.src.box.x = 0; blit.src.box.y = 0; blit.src.box.width = suf->width; blit.src.box.height = suf->height; } blit.mask = PIPE_MASK_RGBA; blit.filter = PIPE_TEX_FILTER_NEAREST; blit.scissor_enable = FALSE; blit.alpha_blend = FALSE; /* blit (and possibly stretch/convert) pixels from This->buffers[0] to * emusurf using u_blit. Windows appears to use NEAREST */ DBG("Blitting (%u..%u)x(%u..%u) to (%u..%u)x(%u..%u).\n", blit.src.box.x, blit.src.box.x + blit.src.box.width, blit.src.box.y, blit.src.box.y + blit.src.box.height, blit.dst.box.x, blit.dst.box.x + blit.dst.box.width, blit.dst.box.y, blit.dst.box.y + blit.dst.box.height); This->pipe->blit(This->pipe, &blit); } if (device->cursor.software && device->cursor.visible && device->cursor.w && blit.dst.resource) { blit.src.resource = device->cursor.image; blit.src.level = 0; blit.src.format = device->cursor.image->format; blit.src.box.x = 0; blit.src.box.y = 0; blit.src.box.width = device->cursor.w; blit.src.box.height = device->cursor.h; ID3DPresent_GetCursorPos(This->present, &device->cursor.pos); /* NOTE: blit messes up when box.x + box.width < 0, fix driver */ blit.dst.box.x = MAX2(device->cursor.pos.x, 0) - device->cursor.hotspot.x; blit.dst.box.y = MAX2(device->cursor.pos.y, 0) - device->cursor.hotspot.y; blit.dst.box.width = blit.src.box.width; blit.dst.box.height = blit.src.box.height; DBG("Blitting cursor(%ux%u) to (%i,%i).\n", blit.src.box.width, blit.src.box.height, blit.dst.box.x, blit.dst.box.y); blit.alpha_blend = TRUE; This->pipe->blit(This->pipe, &blit); } if (device->hud && resource) { hud_draw(device->hud, resource); /* XXX: no offset */ /* HUD doesn't clobber stipple */ NineDevice9_RestoreNonCSOState(device, ~0x2); } This->pipe->flush(This->pipe, NULL, PIPE_FLUSH_END_OF_FRAME); /* really present the frame */ hr = ID3DPresent_Present(This->present, dwFlags); pipe_resource_reference(&resource, NULL); if (FAILED(hr)) { return hr; } return D3D_OK; }