bool fcGraphicsDeviceD3D9::readTexture(void *o_buf, size_t bufsize, void *tex_, int width, int height, fcTextureFormat format)
{
    HRESULT hr;
    IDirect3DTexture9 *tex = (IDirect3DTexture9*)tex_;

    // D3D11 と同様 render target の内容は CPU からはアクセス不可能になっている。
    // staging texture を用意してそれに内容を移し、CPU はそれ経由でデータを読む。
    IDirect3DSurface9 *surf_dst = findOrCreateStagingTexture(width, height, format);
    if (surf_dst == nullptr) { return false; }

    IDirect3DSurface9* surf_src = nullptr;
    hr = tex->GetSurfaceLevel(0, &surf_src);
    if (FAILED(hr)){ return false; }

    bool ret = false;
    hr = m_device->GetRenderTargetData(surf_src, surf_dst);
    if (SUCCEEDED(hr))
    {
        D3DLOCKED_RECT locked;
        hr = surf_dst->LockRect(&locked, nullptr, D3DLOCK_READONLY);
        if (SUCCEEDED(hr))
        {
            char *wpixels = (char*)o_buf;
            int wpitch = width * fcGetPixelSize(format);
            const char *rpixels = (const char*)locked.pBits;
            int rpitch = locked.Pitch;

            // D3D11 と同様表向き解像度と内部解像度が違うケースを考慮
            // (しかし、少なくとも手元の環境では常に wpitch == rpitch っぽい)
            if (wpitch == rpitch)
            {
                memcpy(wpixels, rpixels, bufsize);
            }
            else
            {
                for (int i = 0; i < height; ++i)
                {
                    memcpy(wpixels, rpixels, wpitch);
                    wpixels += wpitch;
                    rpixels += rpitch;
                }
            }
            surf_dst->UnlockRect();

            // D3D9 の ARGB32 のピクセルの並びは BGRA になっているので並べ替える
            if (format == fcTextureFormat_ARGB32) {
                BGRA_RGBA_conversion((RGBA<uint8_t>*)o_buf, bufsize / 4);
            }
            ret = true;
        }
    }

    surf_src->Release();
    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 #3
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 #4
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 #5
0
//----------------------------------------------------------------------------
void PdrRenderTarget::ReadColor (int i, Renderer* renderer,
    Texture2D*& texture)
{
    if (i < 0 || i >= mNumTargets)
    {
        assertion(false, "Invalid target index.\n");
        return;
    }

    IDirect3DDevice9* device = renderer->mData->mDevice;
    HRESULT hr;
    WM5_UNUSED(hr);

    // Enable the input render target surface.
    if (i == 0)
    {
        hr = device->GetRenderTarget(0, &mSaveColorSurface);
        assertion(hr == D3D_OK, "Failed to get old rt 0 color surface: %s\n",
            DXGetErrorString(hr));
    }

    hr = device->SetRenderTarget((DWORD)i, mColorSurfaces[i]);
    assertion(hr == D3D_OK,
        "Failed to set new rt %d color surface: %s\n", i,
        DXGetErrorString(hr));

    // Make a duplicate in system memory.
    IDirect3DTexture9* copyTexture = 0;
    hr = D3DXCreateTexture
    (
        device,
        (UINT)mWidth,
        (UINT)mHeight,
        0,
        0,
        gDX9TextureFormat[mFormat],
        D3DPOOL_SYSTEMMEM,
        &copyTexture
    );
    assertion(hr == D3D_OK,
        "Failed to create copy texture: %s\n",
        DXGetErrorString(hr));

    // Get the surface associated with the copy.
    IDirect3DSurface9* copySurface = 0;
    hr = copyTexture->GetSurfaceLevel(0, &copySurface);
    assertion(hr == D3D_OK,
        "Failed to get surface level for copy texture: %s\n",
        DXGetErrorString(hr));

    // Copy the render target surface.
    hr = device->GetRenderTargetData(mColorSurfaces[i], copySurface);
    assertion(hr == D3D_OK,
        "Failed to copy the rt %d surface: %s\n", i,
        DXGetErrorString(hr));

    // Get the data to write to disk.
    D3DLOCKED_RECT rect;
    hr = copySurface->LockRect(&rect, 0, 0);
    assertion(hr == D3D_OK,
        "Failed to lock copy surface: %s\n",
        DXGetErrorString(hr));

    if (texture)
    {
        if (texture->GetFormat() != mFormat ||
            texture->GetWidth() != (int)mWidth ||
            texture->GetHeight() != (int)mHeight)
        {
            assertion(false, "Incompatible texture.\n");
            delete0(texture);
            texture = new0 Texture2D(mFormat, mWidth, mHeight, 1);
        }
    }
    else
    {
        texture = new0 Texture2D(mFormat, mWidth, mHeight, 1);
    }
    memcpy(texture->GetData(0), rect.pBits, texture->GetNumLevelBytes(0));

    hr = copySurface->UnlockRect();
    assertion(hr == D3D_OK,
        "Failed to unlock copy surface: %s\n",
        DXGetErrorString(hr));

    copySurface->Release();
    copyTexture->Release();

    // Restore the previous render target surface.
    if (i == 0)
    {
        hr = device->SetRenderTarget(0, mSaveColorSurface);
        assertion(hr == D3D_OK,
            "Failed to set old rt 0 color surface: %s\n",
            DXGetErrorString(hr));

        mSaveColorSurface->Release();
    }
}
Beispiel #6
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 #7
0
bool UpdateD3DAntiCheat_ScreenHelpers2( bool lastAttempt )
{
	if( !g_AntiCheat_PrePresentPixels.Count() )
		return false;

	bool result = false;

	HDC windowDC = GetWindowDC( r3dRenderer->HLibWin );

	WINDOWINFO winfo;
	memset( &winfo, 0, sizeof winfo );

	winfo.cbSize = sizeof winfo;

	GetWindowInfo( r3dRenderer->HLibWin, &winfo );

	// put window at 0 0 for convenience
	winfo.rcClient.left -= winfo.rcWindow.left;
	winfo.rcClient.right -= winfo.rcWindow.left;
	winfo.rcClient.top -= winfo.rcWindow.top;
	winfo.rcClient.bottom -= winfo.rcWindow.top;

	winfo.rcWindow.bottom -= winfo.rcWindow.top;
	winfo.rcWindow.top = 0;

	winfo.rcWindow.right -= winfo.rcWindow.left;
	winfo.rcWindow.left = 0;

	int	nTotalWid = winfo.rcWindow.right - winfo.rcWindow.left,
		nTotalHeight = winfo.rcWindow.bottom - winfo.rcWindow.top;

	int nClientWid = winfo.rcClient.right - winfo.rcClient.left,
		nClientHt = winfo.rcClient.bottom - winfo.rcClient.top;

	if( r_fullscreen->GetInt() )
	{
		nTotalWid = g_AntiCheat_PrePresentPixels_Width;
		nTotalHeight = g_AntiCheat_PrePresentPixels_Height;

		nClientWid = g_AntiCheat_PrePresentPixels_Width;
		nClientHt = g_AntiCheat_PrePresentPixels_Height;
	}

	/*if( g_AntiCheat_PrePresentPixels_Width != nClientWid
			||
		g_AntiCheat_PrePresentPixels_Height != nClientHt )
	{
		return false;
	}*/

	HDC hBitmapdc;
	HBITMAP hBitmap, hOriginal;

	if( windowDC || r_fullscreen->GetInt() )
	{
		DWORD* pixel = NULL;

		if( !r_fullscreen->GetInt() )
		{
			hBitmap = CreateCompatibleBitmap(windowDC,nTotalWid,nTotalHeight);

			hBitmapdc = CreateCompatibleDC(windowDC);

			hOriginal = (HBITMAP)SelectBitmap(hBitmapdc, hBitmap);

			BitBlt(	hBitmapdc, 0, 0, nTotalWid, nTotalHeight,
					windowDC, 0, 0, SRCCOPY );

			BITMAPINFO bmpInfo;

			memset( &bmpInfo, 0, sizeof bmpInfo );

			bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
			bmpInfo.bmiHeader.biWidth = nTotalWid;
			bmpInfo.bmiHeader.biHeight = nTotalHeight;
			bmpInfo.bmiHeader.biPlanes = 1;
			bmpInfo.bmiHeader.biBitCount = 32;
			bmpInfo.bmiHeader.biCompression = BI_RGB;
			bmpInfo.bmiHeader.biSizeImage = 0;

			GetDIBits( hBitmapdc, hBitmap, 0, nTotalHeight, NULL, &bmpInfo, DIB_RGB_COLORS );

			r3d_assert( nTotalWid * nTotalHeight * sizeof( DWORD ) <= bmpInfo.bmiHeader.biSizeImage );

			pixel = (DWORD*)malloc( bmpInfo.bmiHeader.biSizeImage );
			GetDIBits( hBitmapdc, hBitmap, 0, nTotalHeight, pixel, &bmpInfo, DIB_RGB_COLORS );

//#if 0
			IDirect3DSurface9 *sysmemBB = r3dRenderer->GetTempSurfaceForScreenShots();

			D3DLOCKED_RECT lrect;
			D3D_V( sysmemBB->LockRect( &lrect, NULL, 0 ) );

			D3DSURFACE_DESC smbbDesc;
			sysmemBB->GetDesc( &smbbDesc );

			r3d_assert( lrect.Pitch * smbbDesc.Height == nClientWid * nClientHt * sizeof( DWORD ) );

			for( int i = 0, e = nClientHt; i < e ; i ++ )
			{
				memcpy( (char*)lrect.pBits + lrect.Pitch * i, pixel + ( nTotalHeight - 1 - ( i + winfo.rcClient.top ) ) * nTotalWid + winfo.rcClient.left, lrect.Pitch );
			}

			D3D_V( sysmemBB->UnlockRect() );

			D3DXSaveSurfaceToFile( "test1.bmp", D3DXIFF_BMP, sysmemBB, NULL, NULL );
//#endif
			DeleteDC( hBitmapdc );
			DeleteObject( hBitmap );
		}
		else
		{
			int pixelDataSize = g_AntiCheat_PrePresentPixels_Width * g_AntiCheat_PrePresentPixels_Height * sizeof( DWORD );

			pixel = (DWORD*)malloc( pixelDataSize );

			struct Locals
			{
				Locals()
				{
					BBuf = 0;
				}

				~Locals()
				{
					if( BBuf ) BBuf->Release();
				}

				IDirect3DSurface9 *BBuf;

			} locals; (void)locals;
			r3dRenderer->GetRT(0, &locals.BBuf);
			
			IDirect3DDevice9 *d = r3dRenderer->pd3ddev;

			IDirect3DSurface9 *sysmemBB = r3dRenderer->GetTempSurfaceForScreenShots();

			if (!SUCCEEDED(d->GetRenderTargetData(locals.BBuf, sysmemBB)))
			{
				r3dOutToLog("SUCCEEDED(d->GetRenderTargetData(locals.BBuf, sysmemBB))\n");
				InvalidateScreenHelperAnticheat();
				return false;
			}

			D3DSURFACE_DESC sdesc;
			sysmemBB->GetDesc( &sdesc );

			D3DLOCKED_RECT lrect;

			sysmemBB->LockRect( &lrect, NULL, D3DLOCK_READONLY );

			r3d_assert( lrect.Pitch * sdesc.Height == pixelDataSize );

			memcpy( pixel, lrect.pBits, lrect.Pitch * sdesc.Height );

			sysmemBB->UnlockRect();

#if 0
			D3DXSaveSurfaceToFile( "test1.jpg", D3DXIFF_JPG, sysmemBB, NULL, NULL );
#endif
		}

		int subAreaHeight = int( nClientHt * 0.8f );
		int subAreaWidth = int( nClientWid * 0.8f );

		int yStart = ( nClientHt - subAreaHeight ) / 2;
		int yEnd = nClientHt - yStart;

		int xStart = ( nClientWid - subAreaWidth ) / 2;
		int xEnd = nClientWid - yStart;

		xStart += winfo.rcClient.left;
		xEnd += winfo.rcClient.left;

		yStart += nTotalHeight - winfo.rcClient.bottom;
		yEnd += nTotalHeight - winfo.rcClient.bottom;

		int totalSubArea = ( xEnd - xStart ) * ( yEnd - yStart );
		int unequalCount = 0;

		//------------------------------------------------------------------------
#if 0
		FILE * fout = fopen( "test0.raw", "wb" );

		for( int y = 0, e = nTotalHeight; y < e; y ++ )
		{
			for( int x = 0, e = nTotalWid; x < e; x ++ )
			{
				fputc( pixel[ x + y * nTotalWid ], fout );
			}
		}

		fclose( fout );

		FILE * fout1 = fopen( "test1.raw", "wb" );

		for( int y = 0, e = nClientHt; y < e; y ++ )
		{
			for( int x = 0, e = nClientWid; x < e; x ++ )
			{
				fputc( g_AntiCheat_PrePresentPixels[ x + y * nClientWid ], fout1 );
			}
		}

		fclose( fout1 );
#endif

		//------------------------------------------------------------------------

		for( int y = yStart, e = yEnd; y < e; y ++ )
		{
			for( int x = xStart, e = xEnd; x < e; x ++ )
			{
				int localX = x - winfo.rcClient.left;
				int localY = 
						r_fullscreen->GetInt() ?
							y - winfo.rcClient.top
								:
							( nTotalHeight - y - 1 ) - winfo.rcClient.top;

				DWORD pixel0 = pixel[ x + y * nTotalWid ] & 0xffffff;
				DWORD pixel1 = g_AntiCheat_PrePresentPixels[ localX + localY * g_AntiCheat_PrePresentPixels_Width ] & 0xffffff;

				if( pixel0 != pixel1 )
				{
					unequalCount ++;
				}
			}
		}

//#if 0
		r3dOutToLog( "unequalCount %d\n", unequalCount );
//#endif

		if( !unequalCount )
		{
			result = true;
		}
		else
		if( lastAttempt )
		{
			result = true;

			// caught some significant extra stuff on screen
			D3DCheaters[ ANTICHEAT_SCREEN_HELPERS2 ] = true;	
			r3dOutToLog("ScreenHelper\n");

			int texWidth = 386;
			int texHeight = 256;

			if( !g_TempSaveDataS )
			{
				D3D_V( r3dRenderer->pd3ddev->CreateTexture( texWidth, texHeight, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &g_TempSaveDataS, NULL ) );
			}

			if( g_TempSaveDataS )
			{
				D3DLOCKED_RECT lrect;

				g_TempSaveDataS->LockRect( 0, &lrect, NULL, 0 );

				r3d_assert( lrect.Pitch == texWidth * sizeof( DWORD ) );

				memset( lrect.pBits, 0, lrect.Pitch * texHeight );

				for( int y=0, yy=0; y < texHeight; y++, yy = y * nClientHt / texHeight )
				{
					for( int x=0, xx=0; x < texWidth; x++, xx = x * nClientWid / texWidth )
					{
						int src_idx = ( nTotalHeight - winfo.rcClient.top - yy - 1 ) * nTotalWid + xx + winfo.rcClient.left;
						if( src_idx < nTotalWid * nTotalHeight )
						{
							if(r_fullscreen->GetInt()) // in fullscreen image in inverted, so write it upside down to correct for that
								*((DWORD*)lrect.pBits + (texHeight-y-1) * texWidth + x) = pixel[ src_idx ];
							else
								*((DWORD*)lrect.pBits + y * texWidth + x) = pixel[ src_idx ];
						}
						else
						{
#ifndef FINAL_BUILD
							r3d_assert(false);
#endif
						}
					}
				}

				g_TempSaveDataS->UnlockRect( 0 );

//#if 0
				D3DXSaveTextureToFile( "test_final.jpg", D3DXIFF_JPG, g_TempSaveDataS, NULL );
//#endif
			}
		}

		free( pixel );

		ReleaseDC( r3dRenderer->HLibWin, windowDC );
	}

	return result;
}
Beispiel #8
0
//------------------------------------------------------------------------
void UpdateD3DAntiCheatPrePresent()
{
	if( !r3dRenderer->DeviceAvailable )
	{
		InvalidateScreenHelperAnticheat();
		return;
	}

	if( EnableD3DAntiCheatCodepath[ ANTICHEAT_SCREEN_HELPERS2 ] )
	{
		if( !g_AntiCheat_PrePresentPixels.Count() )
		{
			IDirect3DDevice9 *d = r3dRenderer->pd3ddev;

			struct Locals
			{
				Locals()
				{
					BBuf = 0;
				}

				~Locals()
				{
					if( BBuf ) BBuf->Release();
				}

				IDirect3DSurface9 *BBuf;

			} locals; (void)locals;

			r3dRenderer->GetRT(0, &locals.BBuf);

			IDirect3DSurface9 *sysmemBB = r3dRenderer->GetTempSurfaceForScreenShots();

			if (!SUCCEEDED(d->GetRenderTargetData(locals.BBuf, sysmemBB)))
			{
				InvalidateScreenHelperAnticheat();
				return;
			}

//#if 0
			D3DXSaveSurfaceToFile( "test0.bmp", D3DXIFF_BMP, sysmemBB, NULL, NULL );
//#endif

			D3DSURFACE_DESC sdesc;
			sysmemBB->GetDesc( &sdesc );

			g_AntiCheat_PrePresentPixels_Width = sdesc.Width;
			g_AntiCheat_PrePresentPixels_Height = sdesc.Height;

			g_AntiCheat_PrePresentPixels.Resize( g_AntiCheat_PrePresentPixels_Width * g_AntiCheat_PrePresentPixels_Height );

			D3DLOCKED_RECT lrect;

			sysmemBB->LockRect( &lrect, NULL, D3DLOCK_READONLY );

			r3d_assert( lrect.Pitch = sdesc.Width * sizeof( DWORD ) );

			memcpy( &g_AntiCheat_PrePresentPixels[ 0 ], lrect.pBits, lrect.Pitch * sdesc.Height );

			sysmemBB->UnlockRect();
		}
	}
}
Beispiel #9
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;
    }
}