IDirect3DSurface9* fcGraphicsDeviceD3D9::findOrCreateStagingTexture(int width, int height, fcTextureFormat format)
{
    if (m_staging_textures.size() >= fcD3D9MaxStagingTextures) {
        clearStagingTextures();
    }

    D3DFORMAT internal_format = fcGetInternalFormatD3D9(format);
    if (internal_format == D3DFMT_UNKNOWN) { return nullptr; }

    uint64_t hash = width + (height << 16) + ((uint64_t)internal_format << 32);
    {
        auto it = m_staging_textures.find(hash);
        if (it != m_staging_textures.end())
        {
            return it->second;
        }
    }

    IDirect3DSurface9 *ret = nullptr;
    HRESULT hr = m_device->CreateOffscreenPlainSurface(width, height, internal_format, D3DPOOL_SYSTEMMEM, &ret, NULL);
    if (SUCCEEDED(hr))
    {
        m_staging_textures.insert(std::make_pair(hash, ret));
    }
    return ret;
}
Beispiel #2
0
IDirect3DSurface9* MythRenderD3D9::CreateSurface(const QSize &size, bool video)
{
    D3D9Locker locker(this);
    IDirect3DDevice9* dev = locker.Acquire();
    if (!dev)
        return NULL;

    IDirect3DSurface9* temp_surface = NULL;

    D3DFORMAT format = video ? m_videosurface_fmt : m_surface_fmt;

    HRESULT hr = dev->CreateOffscreenPlainSurface(
                    size.width(), size.height(), format,
                    D3DPOOL_DEFAULT, &temp_surface, NULL);

    if (FAILED(hr)|| !temp_surface)
    {
        VERBOSE(VB_IMPORTANT, D3DERR + "Failed to create surface.");
        return NULL;
    }

    m_surfaces[temp_surface] = MythD3DSurface(size, format);
    dev->ColorFill(temp_surface, NULL, D3DCOLOR_ARGB(0xFF, 0, 0, 0) );

    return temp_surface;
}
	//-----------------------------------------------------------------------------
	bool D3D9StereoDriverAMD::sendStereoCommand(ATIDX9STEREOCOMMAND stereoCommand, BYTE* outBuffer, DWORD outBufferSize, BYTE* inBuffer, DWORD inBufferSize)
	{
		ATIDX9STEREOCOMMPACKET* stereoCommPacket;
		D3DLOCKED_RECT lockedRect;
		HRESULT stereoPacketResult;

		// If the input buffer exists, verfiy the size is non-zero
		if (inBuffer && inBufferSize == 0)
			return false;

		// If the output buffer exists, verfiy the size is non-zero
		if (outBuffer && outBufferSize == 0)
			return false;

		// If not already created, create a surface to be used to communicate with the driver
		if (NULL == mDriverComSurface)
		{
			// Get the active device from the render system
			D3D9RenderSystem* renderSystem = static_cast<D3D9RenderSystem*>(Root::getSingleton().getRenderSystem());
			IDirect3DDevice9* device = renderSystem->getActiveD3D9Device();
			if (FAILED(device->CreateOffscreenPlainSurface(10, 10, (D3DFORMAT)FOURCC_AQBS, D3DPOOL_DEFAULT, &mDriverComSurface, NULL)))
				return false;
		}

		// Lock the surface and the driver will allocate and return a pointer to a stereo packet
		if (FAILED(mDriverComSurface->LockRect(&lockedRect, 0, 0)))
			return false;

		// Assign the data to the stereo packet
		stereoCommPacket = static_cast<ATIDX9STEREOCOMMPACKET*>(lockedRect.pBits);
		stereoCommPacket->dwSignature = 'STER';
		stereoCommPacket->pResult = &stereoPacketResult;
		stereoCommPacket->stereoCommand = stereoCommand;
		stereoCommPacket->pOutBuffer = outBuffer;
		stereoCommPacket->dwOutBufferSize = outBufferSize;
		stereoCommPacket->pInBuffer = inBuffer;
		stereoCommPacket->dwInBufferSize = inBufferSize;

		// After all bits have been set, unlock the surface
		if (FAILED(mDriverComSurface->UnlockRect()))
			return false;

		// Verify the stereo packet success
		if (FAILED(stereoPacketResult))
			return false;

		return true;
	}
void CSnapShot::GetFrontBufferPixels(UINT uiSizeX, UINT uiSizeY,unsigned char* buffer)
{
	// Get our d3d device
	IDirect3DDevice9 * pDevice = g_pCore->GetGraphics()->GetDevice();

	// Get our display mode
	D3DDISPLAYMODE displayMode;
	pDevice->GetDisplayMode(0, &displayMode);

	// Create our surface
	IDirect3DSurface9 * pSurface = nullptr;
	pDevice->CreateOffscreenPlainSurface(displayMode.Width, displayMode.Height, SCREEN_SHOT_FORMAT, D3DPOOL_SCRATCH, &pSurface, nullptr);

	if(pSurface)
	{
		pDevice->GetFrontBufferData(0, pSurface);

		// Create the client rect
		RECT clientRect;
		{
			POINT clientPoint;
			clientPoint.x = 0;
			clientPoint.y = 0;
			ClientToScreen(*(HWND *)COffsets::VAR_HWnd, &clientPoint);
			clientRect.left   = clientPoint.x;
			clientRect.top	  = clientPoint.y;
			clientRect.right  = (clientRect.left + displayMode.Width);
			clientRect.bottom = (clientRect.top  + displayMode.Height);
		}

		D3DLOCKED_RECT lockedRect;
		HRESULT hr = pSurface->LockRect(&lockedRect, NULL, D3DLOCK_READONLY | D3DLOCK_NOSYSLOCK | D3DLOCK_DONOTWAIT);
	
		if(SUCCEEDED(hr))
		{
			void* pBits = lockedRect.pBits;
			UINT ms_ulPitch = lockedRect.Pitch;

			for(unsigned int i = 0; i < displayMode.Height; ++i)
				memcpy(buffer + (displayMode.Width * 4) * i, (BYTE*)pBits + i * ms_ulPitch, (displayMode.Width * 4));
		}

		pSurface->UnlockRect();
		pSurface->Release();
	}
}
IDirect3DSurface9* CopyToTextureD3D9::findOrCreateStagingTexture(int width, int height)
{
    D3DFORMAT internal_format = D3DFMT_A32B32G32R32F;

    uint64_t hash = width + (height << 16);
    {
        auto it = m_staging_textures.find(hash);
        if (it != m_staging_textures.end())
        {
            return it->second;
        }
    }

    IDirect3DSurface9 *ret = nullptr;
    HRESULT hr = m_device->CreateOffscreenPlainSurface(width, height, internal_format, D3DPOOL_SYSTEMMEM, &ret, NULL);
    if (SUCCEEDED(hr))
    {
        m_staging_textures.insert(std::make_pair(hash, ret));
    }
    return ret;
}
bool Texture2D::GetData(unsigned level, void* dest) const
{
    if (!object_.ptr_)
    {
        ATOMIC_LOGERROR("No texture created, can not get data");
        return false;
    }

    if (!dest)
    {
        ATOMIC_LOGERROR("Null destination for getting data");
        return false;
    }

    if (level >= levels_)
    {
        ATOMIC_LOGERROR("Illegal mip level for getting data");
        return false;
    }

    if (graphics_->IsDeviceLost())
    {
        ATOMIC_LOGWARNING("Getting texture data while device is lost");
        return false;
    }

    int levelWidth = GetLevelWidth(level);
    int levelHeight = GetLevelHeight(level);

    D3DLOCKED_RECT d3dLockedRect;
    RECT d3dRect;
    d3dRect.left = 0;
    d3dRect.top = 0;
    d3dRect.right = levelWidth;
    d3dRect.bottom = levelHeight;

    IDirect3DSurface9* offscreenSurface = 0;
    // Need to use a offscreen surface & GetRenderTargetData() for rendertargets
    if (renderSurface_)
    {
        if (level != 0)
        {
            ATOMIC_LOGERROR("Can only get mip level 0 data from a rendertarget");
            return false;
        }

        IDirect3DDevice9* device = graphics_->GetImpl()->GetDevice();
        HRESULT hr = device->CreateOffscreenPlainSurface((UINT)width_, (UINT)height_, (D3DFORMAT)format_,
            D3DPOOL_SYSTEMMEM, &offscreenSurface, 0);
        if (FAILED(hr))
        {
            ATOMIC_SAFE_RELEASE(offscreenSurface);
            ATOMIC_LOGD3DERROR("Could not create surface for getting rendertarget data", hr);
            return false;
        }
        hr = device->GetRenderTargetData((IDirect3DSurface9*)renderSurface_->GetSurface(), offscreenSurface);
        if (FAILED(hr))
        {
            ATOMIC_LOGD3DERROR("Could not get rendertarget data", hr);
            offscreenSurface->Release();
            return false;
        }
        hr = offscreenSurface->LockRect(&d3dLockedRect, &d3dRect, D3DLOCK_READONLY);
        if (FAILED(hr))
        {
            ATOMIC_LOGD3DERROR("Could not lock surface for getting rendertarget data", hr);
            offscreenSurface->Release();
            return false;
        }
    }
    else
    {
        HRESULT hr = ((IDirect3DTexture9*)object_.ptr_)->LockRect(level, &d3dLockedRect, &d3dRect, D3DLOCK_READONLY);
        if (FAILED(hr))
        {
            ATOMIC_LOGD3DERROR("Could not lock texture", hr);
            return false;
        }
    }

    int height = levelHeight;
    if (IsCompressed())
        height = (height + 3) >> 2;

    unsigned char* destPtr = (unsigned char*)dest;
    unsigned rowSize = GetRowDataSize(levelWidth);
    // GetRowDataSize() returns CPU-side (destination) data size, so need to convert for X8R8G8B8
    if (format_ == D3DFMT_X8R8G8B8)
        rowSize = rowSize / 3 * 4;

    // Perform conversion to RGB / RGBA as necessary
    switch (format_)
    {
    default:
        for (int i = 0; i < height; ++i)
        {
            unsigned char* src = (unsigned char*)d3dLockedRect.pBits + i * d3dLockedRect.Pitch;
            memcpy(destPtr, src, rowSize);
            destPtr += rowSize;
        }
        break;

    case D3DFMT_X8R8G8B8:
        for (int i = 0; i < height; ++i)
        {
            unsigned char* src = (unsigned char*)d3dLockedRect.pBits + i * d3dLockedRect.Pitch;
            for (int j = 0; j < levelWidth; ++j)
            {
                destPtr[2] = *src++;
                destPtr[1] = *src++;
                destPtr[0] = *src++;
                ++src;
                destPtr += 3;
            }
        }
        break;

    case D3DFMT_A8R8G8B8:
        for (int i = 0; i < height; ++i)
        {
            unsigned char* src = (unsigned char*)d3dLockedRect.pBits + i * d3dLockedRect.Pitch;
            for (int j = 0; j < levelWidth; ++j)
            {
                destPtr[2] = *src++;
                destPtr[1] = *src++;
                destPtr[0] = *src++;
                destPtr[3] = *src++;
                destPtr += 4;
            }
        }
        break;
    }

    if (offscreenSurface)
    {
        offscreenSurface->UnlockRect();
        offscreenSurface->Release();
    }
    else
        ((IDirect3DTexture9*)object_.ptr_)->UnlockRect(level);

    return true;
}
Beispiel #7
0
gl::Error Framebuffer9::readPixelsImpl(const gl::Rectangle &area,
                                       GLenum format,
                                       GLenum type,
                                       size_t outputPitch,
                                       const gl::PixelPackState &pack,
                                       uint8_t *pixels) const
{
    ASSERT(pack.pixelBuffer.get() == nullptr);

    const gl::FramebufferAttachment *colorbuffer = mState.getColorAttachment(0);
    ASSERT(colorbuffer);

    RenderTarget9 *renderTarget = nullptr;
    gl::Error error = colorbuffer->getRenderTarget(&renderTarget);
    if (error.isError())
    {
        return error;
    }
    ASSERT(renderTarget);

    IDirect3DSurface9 *surface = renderTarget->getSurface();
    ASSERT(surface);

    D3DSURFACE_DESC desc;
    surface->GetDesc(&desc);

    if (desc.MultiSampleType != D3DMULTISAMPLE_NONE)
    {
        UNIMPLEMENTED();   // FIXME: Requires resolve using StretchRect into non-multisampled render target
        SafeRelease(surface);
        return gl::Error(GL_OUT_OF_MEMORY, "ReadPixels is unimplemented for multisampled framebuffer attachments.");
    }

    IDirect3DDevice9 *device = mRenderer->getDevice();
    ASSERT(device);

    HRESULT result;
    IDirect3DSurface9 *systemSurface = nullptr;
    bool directToPixels = !pack.reverseRowOrder && pack.alignment <= 4 && mRenderer->getShareHandleSupport() &&
                          area.x == 0 && area.y == 0 &&
                          static_cast<UINT>(area.width) == desc.Width && static_cast<UINT>(area.height) == desc.Height &&
                          desc.Format == D3DFMT_A8R8G8B8 && format == GL_BGRA_EXT && type == GL_UNSIGNED_BYTE;
    if (directToPixels)
    {
        // Use the pixels ptr as a shared handle to write directly into client's memory
        result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format,
                                                     D3DPOOL_SYSTEMMEM, &systemSurface, reinterpret_cast<void**>(&pixels));
        if (FAILED(result))
        {
            // Try again without the shared handle
            directToPixels = false;
        }
    }

    if (!directToPixels)
    {
        result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format,
                                                     D3DPOOL_SYSTEMMEM, &systemSurface, nullptr);
        if (FAILED(result))
        {
            ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
            SafeRelease(surface);
            return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal texture for ReadPixels.");
        }
    }

    result = device->GetRenderTargetData(surface, systemSurface);
    SafeRelease(surface);

    if (FAILED(result))
    {
        SafeRelease(systemSurface);

        // It turns out that D3D will sometimes produce more error
        // codes than those documented.
        if (d3d9::isDeviceLostError(result))
        {
            mRenderer->notifyDeviceLost();
        }
        else
        {
            UNREACHABLE();
        }

        return gl::Error(GL_OUT_OF_MEMORY, "Failed to read internal render target data.");
    }

    if (directToPixels)
    {
        SafeRelease(systemSurface);
        return gl::Error(GL_NO_ERROR);
    }

    RECT rect;
    rect.left = gl::clamp(area.x, 0L, static_cast<LONG>(desc.Width));
    rect.top = gl::clamp(area.y, 0L, static_cast<LONG>(desc.Height));
    rect.right = gl::clamp(area.x + area.width, 0L, static_cast<LONG>(desc.Width));
    rect.bottom = gl::clamp(area.y + area.height, 0L, static_cast<LONG>(desc.Height));

    D3DLOCKED_RECT lock;
    result = systemSurface->LockRect(&lock, &rect, D3DLOCK_READONLY);

    if (FAILED(result))
    {
        UNREACHABLE();
        SafeRelease(systemSurface);

        return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal render target.");
    }

    uint8_t *source;
    int inputPitch;
    if (pack.reverseRowOrder)
    {
        source = reinterpret_cast<uint8_t*>(lock.pBits) + lock.Pitch * (rect.bottom - rect.top - 1);
        inputPitch = -lock.Pitch;
    }
    else
    {
        source = reinterpret_cast<uint8_t*>(lock.pBits);
        inputPitch = lock.Pitch;
    }

    const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(desc.Format);
    const gl::InternalFormat &sourceFormatInfo = gl::GetInternalFormatInfo(d3dFormatInfo.internalFormat);
    if (sourceFormatInfo.format == format && sourceFormatInfo.type == type)
    {
        // Direct copy possible
        for (int y = 0; y < rect.bottom - rect.top; y++)
        {
            memcpy(pixels + y * outputPitch, source + y * inputPitch, (rect.right - rect.left) * sourceFormatInfo.pixelBytes);
        }
    }
    else
    {
        const d3d9::D3DFormat &sourceD3DFormatInfo = d3d9::GetD3DFormatInfo(desc.Format);
        ColorCopyFunction fastCopyFunc = sourceD3DFormatInfo.getFastCopyFunction(format, type);

        GLenum sizedDestInternalFormat = gl::GetSizedInternalFormat(format, type);
        const gl::InternalFormat &destFormatInfo = gl::GetInternalFormatInfo(sizedDestInternalFormat);

        if (fastCopyFunc)
        {
            // Fast copy is possible through some special function
            for (int y = 0; y < rect.bottom - rect.top; y++)
            {
                for (int x = 0; x < rect.right - rect.left; x++)
                {
                    uint8_t *dest = pixels + y * outputPitch + x * destFormatInfo.pixelBytes;
                    const uint8_t *src = source + y * inputPitch + x * sourceFormatInfo.pixelBytes;

                    fastCopyFunc(src, dest);
                }
            }
        }
        else
        {
            ColorReadFunction colorReadFunction = sourceD3DFormatInfo.colorReadFunction;
            ColorWriteFunction colorWriteFunction = GetColorWriteFunction(format, type);

            uint8_t temp[sizeof(gl::ColorF)];
            for (int y = 0; y < rect.bottom - rect.top; y++)
            {
                for (int x = 0; x < rect.right - rect.left; x++)
                {
                    uint8_t *dest = pixels + y * outputPitch + x * destFormatInfo.pixelBytes;
                    const uint8_t *src = source + y * inputPitch + x * sourceFormatInfo.pixelBytes;

                    // readFunc and writeFunc will be using the same type of color, CopyTexImage
                    // will not allow the copy otherwise.
                    colorReadFunction(src, temp);
                    colorWriteFunction(temp, dest);
                }
            }
        }
    }

    systemSurface->UnlockRect();
    SafeRelease(systemSurface);

    return gl::Error(GL_NO_ERROR);
}
Beispiel #8
0
gl::Error Framebuffer9::readPixelsImpl(const gl::Context *context,
                                       const gl::Rectangle &area,
                                       GLenum format,
                                       GLenum type,
                                       size_t outputPitch,
                                       const gl::PixelPackState &pack,
                                       uint8_t *pixels)
{
    const gl::FramebufferAttachment *colorbuffer = mState.getColorAttachment(0);
    ASSERT(colorbuffer);

    RenderTarget9 *renderTarget = nullptr;
    ANGLE_TRY(colorbuffer->getRenderTarget(context, &renderTarget));
    ASSERT(renderTarget);

    IDirect3DSurface9 *surface = renderTarget->getSurface();
    ASSERT(surface);

    D3DSURFACE_DESC desc;
    surface->GetDesc(&desc);

    if (desc.MultiSampleType != D3DMULTISAMPLE_NONE)
    {
        UNIMPLEMENTED();   // FIXME: Requires resolve using StretchRect into non-multisampled render target
        SafeRelease(surface);
        return gl::OutOfMemory()
               << "ReadPixels is unimplemented for multisampled framebuffer attachments.";
    }

    IDirect3DDevice9 *device = mRenderer->getDevice();
    ASSERT(device);

    HRESULT result;
    IDirect3DSurface9 *systemSurface = nullptr;
    bool directToPixels = !pack.reverseRowOrder && pack.alignment <= 4 && mRenderer->getShareHandleSupport() &&
                          area.x == 0 && area.y == 0 &&
                          static_cast<UINT>(area.width) == desc.Width && static_cast<UINT>(area.height) == desc.Height &&
                          desc.Format == D3DFMT_A8R8G8B8 && format == GL_BGRA_EXT && type == GL_UNSIGNED_BYTE;
    if (directToPixels)
    {
        // Use the pixels ptr as a shared handle to write directly into client's memory
        result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format,
                                                     D3DPOOL_SYSTEMMEM, &systemSurface, reinterpret_cast<void**>(&pixels));
        if (FAILED(result))
        {
            // Try again without the shared handle
            directToPixels = false;
        }
    }

    if (!directToPixels)
    {
        result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format,
                                                     D3DPOOL_SYSTEMMEM, &systemSurface, nullptr);
        if (FAILED(result))
        {
            ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
            SafeRelease(surface);
            return gl::OutOfMemory() << "Failed to allocate internal texture for ReadPixels.";
        }
    }

    result = device->GetRenderTargetData(surface, systemSurface);
    SafeRelease(surface);

    if (FAILED(result))
    {
        SafeRelease(systemSurface);

        // It turns out that D3D will sometimes produce more error
        // codes than those documented.
        if (d3d9::isDeviceLostError(result))
        {
            mRenderer->notifyDeviceLost();
        }
        else
        {
            UNREACHABLE();
        }

        return gl::OutOfMemory() << "Failed to read internal render target data.";
    }

    if (directToPixels)
    {
        SafeRelease(systemSurface);
        return gl::NoError();
    }

    RECT rect;
    rect.left = gl::clamp(area.x, 0L, static_cast<LONG>(desc.Width));
    rect.top = gl::clamp(area.y, 0L, static_cast<LONG>(desc.Height));
    rect.right = gl::clamp(area.x + area.width, 0L, static_cast<LONG>(desc.Width));
    rect.bottom = gl::clamp(area.y + area.height, 0L, static_cast<LONG>(desc.Height));

    D3DLOCKED_RECT lock;
    result = systemSurface->LockRect(&lock, &rect, D3DLOCK_READONLY);

    if (FAILED(result))
    {
        UNREACHABLE();
        SafeRelease(systemSurface);

        return gl::OutOfMemory() << "Failed to lock internal render target.";
    }

    uint8_t *source = reinterpret_cast<uint8_t *>(lock.pBits);
    int inputPitch  = lock.Pitch;

    const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(desc.Format);
    gl::FormatType formatType(format, type);

    PackPixelsParams packParams;
    packParams.area.x      = rect.left;
    packParams.area.y      = rect.top;
    packParams.area.width  = rect.right - rect.left;
    packParams.area.height = rect.bottom - rect.top;
    packParams.format      = format;
    packParams.type        = type;
    packParams.outputPitch = static_cast<GLuint>(outputPitch);
    packParams.pack        = pack;

    PackPixels(packParams, d3dFormatInfo.info(), inputPitch, source, pixels);

    systemSurface->UnlockRect();
    SafeRelease(systemSurface);

    return gl::NoError();
}
Beispiel #9
0
bool TextureCube::GetData(CubeMapFace face, unsigned level, void* dest) const
{
    if (!object_.ptr_)
    {
        URHO3D_LOGERROR("No texture created, can not get data");
        return false;
    }

    if (!dest)
    {
        URHO3D_LOGERROR("Null destination for getting data");
        return false;
    }

    if (level >= levels_)
    {
        URHO3D_LOGERROR("Illegal mip level for getting data");
        return false;
    }

    if (graphics_->IsDeviceLost())
    {
        URHO3D_LOGWARNING("Getting texture data while device is lost");
        return false;
    }

    if (resolveDirty_)
        graphics_->ResolveToTexture(const_cast<TextureCube*>(this));

    int levelWidth = GetLevelWidth(level);
    int levelHeight = GetLevelHeight(level);

    D3DLOCKED_RECT d3dLockedRect;
    RECT d3dRect;
    d3dRect.left = 0;
    d3dRect.top = 0;
    d3dRect.right = levelWidth;
    d3dRect.bottom = levelHeight;

    IDirect3DSurface9* offscreenSurface = nullptr;
    // Need to use a offscreen surface & GetRenderTargetData() for rendertargets
    if (renderSurfaces_[face])
    {
        if (level != 0)
        {
            URHO3D_LOGERROR("Can only get mip level 0 data from a rendertarget");
            return false;
        }

        // If multisampled, must copy the surface of the resolve texture instead of the multisampled surface
        IDirect3DSurface9* resolveSurface = nullptr;
        if (multiSample_ > 1)
        {
            HRESULT hr = ((IDirect3DCubeTexture9*)object_.ptr_)->GetCubeMapSurface((D3DCUBEMAP_FACES)face, 0,
                (IDirect3DSurface9**)&resolveSurface);
            if (FAILED(hr))
            {
                URHO3D_LOGD3DERROR("Could not get surface of the resolve texture", hr);
                URHO3D_SAFE_RELEASE(resolveSurface);
                return false;
            }
        }

        IDirect3DDevice9* device = graphics_->GetImpl()->GetDevice();
        HRESULT hr = device->CreateOffscreenPlainSurface((UINT)width_, (UINT)height_, (D3DFORMAT)format_, D3DPOOL_SYSTEMMEM, &offscreenSurface, nullptr);
        if (FAILED(hr))
        {
            URHO3D_LOGD3DERROR("Could not create surface for getting rendertarget data", hr);
            URHO3D_SAFE_RELEASE(offscreenSurface);
            URHO3D_SAFE_RELEASE(resolveSurface);
            return false;
        }

        if (resolveSurface)
            hr = device->GetRenderTargetData(resolveSurface, offscreenSurface);
        else
            hr = device->GetRenderTargetData((IDirect3DSurface9*)renderSurfaces_[face]->GetSurface(), offscreenSurface);
        URHO3D_SAFE_RELEASE(resolveSurface);

        if (FAILED(hr))
        {
            URHO3D_LOGD3DERROR("Could not get rendertarget data", hr);
            URHO3D_SAFE_RELEASE(offscreenSurface);
            return false;
        }
        if (FAILED(offscreenSurface->LockRect(&d3dLockedRect, &d3dRect, D3DLOCK_READONLY)))
        {
            URHO3D_LOGD3DERROR("Could not lock surface for getting rendertarget data", hr);
            URHO3D_SAFE_RELEASE(offscreenSurface);
            return false;
        }
    }
    else
    {
        HRESULT hr = ((IDirect3DCubeTexture9*)object_.ptr_)->LockRect((D3DCUBEMAP_FACES)face, level, &d3dLockedRect, &d3dRect, D3DLOCK_READONLY);
        if (FAILED(hr))
        {
            URHO3D_LOGD3DERROR("Could not lock texture", hr);
            return false;
        }
    }

    int height = levelHeight;
    if (IsCompressed())
        height = (height + 3) >> 2;

    unsigned char* destPtr = (unsigned char*)dest;
    unsigned rowSize = GetRowDataSize(levelWidth);
    // GetRowDataSize() returns CPU-side (destination) data size, so need to convert for X8R8G8B8
    if (format_ == D3DFMT_X8R8G8B8)
        rowSize = rowSize / 3 * 4;

    // Perform conversion to RGB / RGBA as necessary
    switch (format_)
    {
    default:
        for (int i = 0; i < height; ++i)
        {
            unsigned char* src = (unsigned char*)d3dLockedRect.pBits + i * d3dLockedRect.Pitch;
            memcpy(destPtr, src, rowSize);
            destPtr += rowSize;
        }
        break;

    case D3DFMT_X8R8G8B8:
        for (int i = 0; i < height; ++i)
        {
            unsigned char* src = (unsigned char*)d3dLockedRect.pBits + i * d3dLockedRect.Pitch;
            for (int j = 0; j < levelWidth; ++j)
            {
                destPtr[2] = *src++;
                destPtr[1] = *src++;
                destPtr[0] = *src++;
                ++src;
                destPtr += 3;
            }
        }
        break;

    case D3DFMT_A8R8G8B8:
        for (int i = 0; i < height; ++i)
        {
            unsigned char* src = (unsigned char*)d3dLockedRect.pBits + i * d3dLockedRect.Pitch;
            for (int j = 0; j < levelWidth; ++j)
            {
                destPtr[2] = *src++;
                destPtr[1] = *src++;
                destPtr[0] = *src++;
                destPtr[3] = *src++;
                destPtr += 4;
            }
        }
        break;
    }

    if (offscreenSurface)
        offscreenSurface->UnlockRect();
    else
        ((IDirect3DCubeTexture9*)object_.ptr_)->UnlockRect((D3DCUBEMAP_FACES)face, level);

    URHO3D_SAFE_RELEASE(offscreenSurface);
    return true;
}
Beispiel #10
0
HRESULT WINAPI D3D9SCPresent(IDirect3DSwapChain9 *pSc, CONST RECT* pSourceRect,CONST RECT* pDestRect,HWND hDestWindowOverride,CONST RGNDATA* pDirtyRegion, DWORD dwFlags) {

    D3D9FrameGrabber *d3d9FrameGrabber = D3D9FrameGrabber::getInstance();
    Logger *logger = d3d9FrameGrabber->m_logger;
    DWORD errorcode;
    if (WAIT_OBJECT_0 == (errorcode = WaitForSingleObject(d3d9FrameGrabber->m_syncRunMutex, 0))) {
        IPCContext *ipcContext = d3d9FrameGrabber->m_ipcContext;
        logger->reportLogDebug(L"D3D9SCPresent");
        IDirect3DSurface9 *pBackBuffer = NULL;
        D3DPRESENT_PARAMETERS params;
        RECT newRect = RECT();
        IDirect3DSurface9 *pDemultisampledSurf = NULL;
        IDirect3DSurface9 *pOffscreenSurf = NULL;
        IDirect3DDevice9 *pDev = NULL;

        HRESULT hRes = pSc->GetPresentParameters(&params);

        if (FAILED(hRes) || params.Windowed) {
            goto end;
        }

        if (FAILED(hRes = pSc->GetBackBuffer( 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer))) {
            logger->reportLogError(L"d3d9sc couldn't get backbuffer. errorcode = 0x%x", hRes);
            goto end;
        }
        D3DSURFACE_DESC surfDesc;
        pBackBuffer->GetDesc(&surfDesc);

        hRes = pSc->GetDevice(&pDev);
        if (FAILED(hRes))
        {
            logger->reportLogError(L"GetFramePrep: FAILED to get pDev. 0x%x, width=%u, height=%u, format=%x", hRes, surfDesc.Width, surfDesc.Height, surfDesc.Format );
            goto end;
        }
        hRes = pDev->CreateRenderTarget(
            surfDesc.Width, surfDesc.Height,
            surfDesc.Format, D3DMULTISAMPLE_NONE, 0, false,
            &pDemultisampledSurf, NULL );
        if (FAILED(hRes))
        {
            logger->reportLogError(L"GetFramePrep: FAILED to create demultisampled render target. 0x%x, width=%u, height=%u, format=%x", hRes, surfDesc.Width, surfDesc.Height, surfDesc.Format );
            goto end;
        }

        hRes = pDev->StretchRect(pBackBuffer, NULL, pDemultisampledSurf, NULL, D3DTEXF_LINEAR );
        if (FAILED(hRes))
        {
            logger->reportLogError(L"GetFramePrep: StretchRect FAILED for image surfacee. 0x%x, width=%u, height=%u, format=%x", hRes, surfDesc.Width, surfDesc.Height, surfDesc.Format );
            goto end;
        }

        hRes = pDev->CreateOffscreenPlainSurface(
            surfDesc.Width, surfDesc.Height,
            surfDesc.Format, D3DPOOL_SYSTEMMEM,
            &pOffscreenSurf, NULL );
        if (FAILED(hRes))
        {
            logger->reportLogError(L"GetFramePrep: FAILED to create image surface. 0x%x, width=%u, height=%u, format=%x", hRes, surfDesc.Width, surfDesc.Height, surfDesc.Format );
            goto end;
        }

        hRes = pDev->GetRenderTargetData(pDemultisampledSurf, pOffscreenSurf );
        if (FAILED(hRes))
        {
            logger->reportLogError(L"GetFramePrep: GetRenderTargetData() FAILED for image surfacee. 0x%x, width=%u, height=%u, format=%x", hRes, surfDesc.Width, surfDesc.Height, surfDesc.Format );
            goto end;
        }

        D3DLOCKED_RECT lockedSrcRect;
        newRect.right = surfDesc.Width;
        newRect.bottom = surfDesc.Height;

        hRes = pOffscreenSurf->LockRect( &lockedSrcRect, &newRect, 0);
        if (FAILED(hRes))
        {
            logger->reportLogError(L"GetFramePrep: FAILED to lock source rect. (0x%x)", hRes );
            goto end;
        }

        ipcContext->m_memDesc.width = surfDesc.Width;
        ipcContext->m_memDesc.height = surfDesc.Height;
        ipcContext->m_memDesc.rowPitch = lockedSrcRect.Pitch;
        ipcContext->m_memDesc.frameId++;
        ipcContext->m_memDesc.format = getCompatibleBufferFormat(surfDesc.Format);

        if (WAIT_OBJECT_0 == (errorcode = WaitForSingleObject(ipcContext->m_hMutex, 0))) {
            //            __asm__("int $3");
    //        reportLog(EVENTLOG_INFORMATION_TYPE, L"d3d9sc writing description to mem mapped file");
            memcpy(ipcContext->m_pMemMap, &ipcContext->m_memDesc, sizeof (ipcContext->m_memDesc));
    //        reportLog(EVENTLOG_INFORMATION_TYPE, L"d3d9sc writing data to mem mapped file");
            PVOID pMemDataMap = incPtr(ipcContext->m_pMemMap, sizeof (ipcContext->m_memDesc));
            if (static_cast<UINT>(lockedSrcRect.Pitch) == surfDesc.Width * 4) {
                memcpy(pMemDataMap, lockedSrcRect.pBits, surfDesc.Width * surfDesc.Height * 4);
            } else {
                UINT i = 0, cleanOffset = 0, pitchOffset = 0;
                while (i < surfDesc.Height) {
                    memcpy(incPtr(pMemDataMap, cleanOffset), incPtr(lockedSrcRect.pBits, pitchOffset), surfDesc.Width * 4);
                    cleanOffset += surfDesc.Width * 4;
                    pitchOffset += lockedSrcRect.Pitch;
                    i++;
                }
            }
            ReleaseMutex(ipcContext->m_hMutex);
            SetEvent(ipcContext->m_hFrameGrabbedEvent);
        } else {
            logger->reportLogError(L"d3d9sc couldn't wait mutex. errocode = 0x%x", errorcode);
        }
end:
        if(pOffscreenSurf) pOffscreenSurf->Release();
        if(pDemultisampledSurf) pDemultisampledSurf->Release();
        if(pBackBuffer) pBackBuffer->Release();
        if(pDev) pDev->Release();

        ProxyFuncJmp *d3d9SCPresentProxyFuncJmp = d3d9FrameGrabber->m_d3d9SCPresentProxyFuncJmp;

        if(d3d9SCPresentProxyFuncJmp->removeHook()) {
            int i = GetLastError();
            logger->reportLogError(L"d3d9sc error occured while trying to removeHook before original call0x%x", i);
        }
        HRESULT result = pSc->Present(pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, dwFlags);

        if(d3d9SCPresentProxyFuncJmp->installHook()) {
            int i = GetLastError();
            logger->reportLogError(L"d3d9sc error occured while trying to installHook after original call0x%x", i);
        }

        ReleaseMutex(d3d9FrameGrabber->m_syncRunMutex);

        return result;
    } else {
        logger->reportLogError(L"d3d9sc present is skipped because mutex is busy");
        return S_FALSE;
    }
}