Changes to pixels in a texture not visible

Discussion area about developing with Ogre-Next (2.1, 2.2 and beyond)


Post Reply
Hotshot5000
OGRE Contributor
OGRE Contributor
Posts: 226
Joined: Thu Oct 14, 2010 12:30 pm
x 56

Changes to pixels in a texture not visible

Post by Hotshot5000 »

I have a texture defined like this:

Code: Select all

abstract hlms BaseSettingsAlphaBlend unlit
{
	scene_blend	alpha_blend
	depth_check	off
	depth_write	off
	cull_mode	none
}
hlms radar_mat unlit : BaseSettingsAlphaBlend
{
	diffuse_map radar.png
}
This texture is used in an overlay element that gets drawn to the screen. Everything looks normal so far.

So I try to change some pixels in the texture like so:

Code: Select all

void DynamicOverlayElement::lock() {
    const Ogre::TexturePtr &texture = datablock->getTexture(0);
    const Ogre::v1::HardwarePixelBufferSharedPtr &hardwarePixelBuffer = texture->getBuffer();
    currentBuffer = hardwarePixelBuffer.getPointer();
    const Ogre::PixelBox &box = hardwarePixelBuffer->lock(Ogre::Image::Box(0, 0, 0, 
        hardwarePixelBuffer->getWidth(), 
        hardwarePixelBuffer->getHeight(), 1), Ogre::v1::HardwarePixelBuffer::LockOptions::HBL_NORMAL);
    currentLock = (Ogre::PixelBox *) &box;
}

void DynamicOverlayElement::unlock() {
    currentBuffer->unlock();
    currentLock = NULL;
//    lockPtr = NULL;
}

DynamicOverlayBox DynamicOverlayElement::setAreaToColor(Ogre::Box &rect,
                                                                          std::vector<Ogre::ColourValue> &val,
                                                                          bool overwriteTransparentPixels) {
    if (rect.getWidth() * rect.getHeight() != val.size())
    {
        ::Ogre::String errorStr("rect width: " + SSTR(rect.getWidth()) +
                                " height: " + SSTR(rect.getHeight()) +
                                " different from colour size: " + SSTR(val.size()));
        LOGI("%s", errorStr.c_str());
        exit(-1);
    }
    rect.left = std::max(rect.left, currentLock->left);
    rect.top = std::max(rect.top, currentLock->top);
    rect.front = std::max(rect.front, currentLock->front);
    rect.right = std::min(rect.right, currentLock->right);
    rect.bottom = std::min(rect.bottom, currentLock->bottom);
    rect.back = std::min(rect.back, currentLock->back);
    const Ogre::PixelBox &volume = currentLock->getSubVolume(rect);
    size_t bytesPerPixel = Ogre::PixelUtil::getNumElemBytes(currentLock->format);
    Hotshot::DynamicOverlayBox oldElement;
    oldElement.rect = rect;
    int colorPos = 0;
    int* data = (int *) volume.data;
    for (int y = 0; y < volume.bottom; ++y)
    {
        for (int x = 0; x < volume.right; ++x) {
            Ogre::ColourValue oldCol;
            int prevData = *data;
            switch (currentLock->format) {
                case Ogre::PF_A8R8G8B8:
#if O32_HOST_ORDER == O32_LITTLE_ENDIAN
                    oldCol.setAsBGRA(prevData);
#else
                    oldCol.setAsARGB(prevData);
#endif

                    break;
                case Ogre::PF_R8G8B8A8:
#if O32_HOST_ORDER == O32_LITTLE_ENDIAN
                    oldCol.setAsABGR(prevData);
#else
                    oldCol.setAsRGBA(prevData);
#endif

                    break;
                default:
                    LOGI("%s", "Only A8R8G8B8 and R8G8B8A8");
                    exit(-1);
            }
            // Add it anyway for corner cases when even though we don't
            // overwrite we still need the value for when we reset the texture
            oldElement.color.push_back(oldCol);
            if (!overwriteTransparentPixels && oldCol.a == 0.0f) {
                // Don't forget to add the offset!!!!!!
                ++data;
                continue;
            }
            Ogre::ColourValue &newCol = val[colorPos];
            int newData;
            switch (currentLock->format) {
                case Ogre::PF_A8R8G8B8:
#if O32_HOST_ORDER == O32_LITTLE_ENDIAN
                    newData = newCol.getAsBGRA();
#else
                    newData = newCol.getAsARGB();
#endif

                    break;
                case Ogre::PF_R8G8B8A8:
#if O32_HOST_ORDER == O32_LITTLE_ENDIAN
                    newData = newCol.getAsABGR();
#else
                    newData = newCol.getAsRGBA();
#endif

                    break;
                default:
                    LOGI("%s", "Only A8R8G8B8 and R8G8B8A8");
                    exit(-1);
            }
            *data++ = newData;
        }
        data += currentLock->getRowSkip();

    }
    return oldElement;
}
The important thing to note is that the values do get updated. If I write a white pixel, next time I call setAreaToColor() the pixel that I read is white, so something gets saved, it's just that it doesn't seem to get to the screen. From what I dug, the texture uses HBL_NORMAL and uses staging buffers in DX11 backend.

Is this normal behavior, not to be able to update textures once they get in a texture array?

EDIT: If I just lock the texture buffer I get

Code: Select all

D3D11 ERROR: ID3D11DeviceContext::CopySubresourceRegion: pSrcBox is not a valid box for the source subresource. *pSrcBox = { left:0, top:0, front:0, right:64, bottom:64, back:40 }. SrcSubresource = { left:0, top:0, front:0, right:64, bottom:64, back:1 }. [ RESOURCE_MANIPULATION ERROR #280: COPYSUBRESOURCEREGION_INVALIDSOURCEBOX]
D3D11 ERROR: ID3D11DeviceContext::CopySubresourceRegion: When offset by the destination coordinates, pSrcBox does not fit on the destination subresource. OffsetSrcBox = { left:0, top:0, front:0, right:64, bottom:64, back:40 }. DstSubresource = { left:0, top:0, front:0, right:64, bottom:64, back:1 }. [ RESOURCE_MANIPULATION ERROR #280: COPYSUBRESOURCEREGION_INVALIDSOURCEBOX]
D3D11 ERROR: ID3D11DeviceContext::CopySubresourceRegion: pSrcBox is not a valid box for the source subresource. *pSrcBox = { left:0, top:0, front:0, right:64, bottom:64, back:40 }. SrcSubresource = { left:0, top:0, front:0, right:64, bottom:64, back:1 }. [ RESOURCE_MANIPULATION ERROR #280: COPYSUBRESOURCEREGION_INVALIDSOURCEBOX]
D3D11 ERROR: ID3D11DeviceContext::CopySubresourceRegion: When offset by the destination coordinates, pSrcBox does not fit on the destination subresource. OffsetSrcBox = { left:0, top:0, front:0, right:64, bottom:64, back:40 }. DstSubresource = { left:0, top:0, front:0, right:64, bottom:64, back:1 }. [ RESOURCE_MANIPULATION ERROR #280: COPYSUBRESOURCEREGION_INVALIDSOURCEBOX]
I need to lock the buffer with depth == 1 since it looks like it locks all the mipmaps and D3D doesn't seem to like that.
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5296
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1278
Contact:

Re: Changes to pixels in a texture not visible

Post by dark_sylinc »

The problem is that texture arrays go from back to front, and you're handling them front to back.

I made the same mistake as well which is why on Ogre 2.2 TextureBox will be using a less confusing naming convention (z and depth, and sliceStart and numSlices).

Edit: Considering you'll be updating your radar sort of often (e.g. every frame); I'd suggest you load the radar.png texture from C++ (i.e. via TextureManager::getSingleton().load() ) so it is 2D instead of 2D Array, and assign the texture to the datablock via C++ (Unlit supports regular 2D textures, PBS does not).
Having it as an array just to update one slice every frame might end up giving you unknown/unexpected performance penalties.
Hotshot5000
OGRE Contributor
OGRE Contributor
Posts: 226
Joined: Thu Oct 14, 2010 12:30 pm
x 56

Re: Changes to pixels in a texture not visible

Post by Hotshot5000 »

I've done:

Code: Select all

const Ogre::TexturePtr &ptr = Ogre::TextureManager::getSingleton().load("radar.png", "Essential");
    datablock->setTexture(0, 0, ptr);
aaaand now it's working! Weeeeee! Thanks very much!
Post Reply