OGRECave / ogre

scene-oriented, flexible 3D engine (C++, Python, C#, Java)
https://ogrecave.github.io/ogre/
MIT License
4k stars 981 forks source link

Can't read a texture texel color with DirectX11: pixelBox gives random results with non-power of 2 textures #3107

Closed corentinjaffre closed 6 months ago

corentinjaffre commented 6 months ago

Ogre 13.6.5 and Dx11:

I'm reading a texture texel color for my asset selection in the editor (to know if a given object alpha is >0 or not), and as it works perfectly with DX9, it doesn't with Dx11, depending on the texture width.

My code:

       // Lock the texture
    Ogre::HardwarePixelBufferSharedPtr tmpHardwarePixelBuffer = texture->getBuffer(0, 0);
    tmpHardwarePixelBuffer->lock(Ogre::HardwareBuffer::HBL_READ_ONLY);
    const Ogre::PixelBox& tmpPixelBox = tmpHardwarePixelBuffer->getCurrentLock();
    unsigned char* tmpData = static_cast<unsigned char*>(tmpPixelBox.data);
    size_t tmpWidth = tmpPixelBox.getWidth();
    size_t tmpHeight = tmpPixelBox.getHeight();
    size_t tmpRowPitch = tmpPixelBox.rowPitch;
    size_t tmpDataIndexStep = PixelUtil::getNumElemBytes(tmpPixelBox.format);

// Return the pixel colour at the UV in the texture
    size_t tmpPixelX = (size_t)(uv.x * (float)(tmpWidth - 1));
    size_t tmpPixelY = (size_t)(uv.y * (float)(tmpHeight - 1));

    ColourValue tmpColour = ColourValue(0.0f, 0.0f, 0.0f, 1.0f);
       int tmpDataIndex = 0;
        bool tmpFoundPixel = false;
        for (int y = 0; y < tmpHeight; ++y)
        {
            for (int x = 0; x < tmpWidth; ++x)
            {
                // Check if we have reached the pixel we were looking for
                if (tmpPixelX == x &&
                    tmpPixelY == y)
                {
                    // Get the colour from the pixel
                    PixelUtil::unpackColour(&tmpColour, tmpPixelBox.format, tmpData + tmpDataIndex);
                    tmpFoundPixel = true;
                    // Break out of the loop, we are done
                    break;
                }

                tmpDataIndex += tmpDataIndexStep;
            }

            if (tmpFoundPixel)
                // Break out of the loop, we are done
                break;
        }
    }
    else
        bool error = true;
(...)

    // Unlock the texture
    tmpHardwarePixelBuffer->unlock();

This code works for anything with Dx9, but with Dx11 I get random color results if the texture width is not 64, 96, or 128. With a texture width of 64, I get the right colors, not if the width is 65.

paroj commented 6 months ago

you are not handling rowPitch in your code, which is ok for D3D9, but needed for D3D11: https://stackoverflow.com/questions/70005258/why-does-the-function-id3d11devicecontextmap-sometimes-produce-a-mapped-subres

use blitToMemory for a quick test

corentinjaffre commented 6 months ago

Oh, thanks a lot!