Exemplo n.º 1
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);
}
Exemplo n.º 2
0
void PackPixels(const PackPixelsParams &params,
                const angle::Format &sourceFormat,
                int inputPitchIn,
                const uint8_t *sourceIn,
                uint8_t *destWithoutOffset)
{
    uint8_t *destWithOffset = destWithoutOffset + params.offset;

    const uint8_t *source = sourceIn;
    int inputPitch        = inputPitchIn;

    if (params.pack.reverseRowOrder)
    {
        source += inputPitch * (params.area.height - 1);
        inputPitch = -inputPitch;
    }

    const auto &sourceGLInfo = gl::GetSizedInternalFormatInfo(sourceFormat.glInternalFormat);

    if (sourceGLInfo.format == params.format && sourceGLInfo.type == params.type)
    {
        // Direct copy possible
        for (int y = 0; y < params.area.height; ++y)
        {
            memcpy(destWithOffset + y * params.outputPitch, source + y * inputPitch,
                   params.area.width * sourceGLInfo.pixelBytes);
        }
        return;
    }

    ASSERT(sourceGLInfo.sized);

    gl::FormatType formatType(params.format, params.type);
    ColorCopyFunction fastCopyFunc =
        GetFastCopyFunction(sourceFormat.fastCopyFunctions, formatType);
    const auto &destFormatInfo = gl::GetInternalFormatInfo(formatType.format, formatType.type);

    if (fastCopyFunc)
    {
        // Fast copy is possible through some special function
        for (int y = 0; y < params.area.height; ++y)
        {
            for (int x = 0; x < params.area.width; ++x)
            {
                uint8_t *dest =
                    destWithOffset + y * params.outputPitch + x * destFormatInfo.pixelBytes;
                const uint8_t *src = source + y * inputPitch + x * sourceGLInfo.pixelBytes;

                fastCopyFunc(src, dest);
            }
        }
        return;
    }

    ColorWriteFunction colorWriteFunction = GetColorWriteFunction(formatType);

    // Maximum size of any Color<T> type used.
    uint8_t temp[16];
    static_assert(sizeof(temp) >= sizeof(gl::ColorF) && sizeof(temp) >= sizeof(gl::ColorUI) &&
                      sizeof(temp) >= sizeof(gl::ColorI),
                  "Unexpected size of gl::Color struct.");

    const auto &colorReadFunction = sourceFormat.colorReadFunction;

    for (int y = 0; y < params.area.height; ++y)
    {
        for (int x = 0; x < params.area.width; ++x)
        {
            uint8_t *dest      = destWithOffset + y * params.outputPitch + x * destFormatInfo.pixelBytes;
            const uint8_t *src = source + y * inputPitch + x * sourceGLInfo.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);
        }
    }
}