Why is the image from the CUDA version not as sharp as the CPU version? I am extending Roger Allen's Ray Tracing in One Weekend in CUDA (and also here) by following Peter Shirley's Ray Tracing: The Next Week; specifically Image Texture Mapping.
The image I obtain from CUDA is not as sharp as the CPU version. Shirley's book uses double and Allen restricts to float but could that be the only reason?
The texture source for both is a 24 bit depth jpeg file.
In both cases 100x sampling per pixel used for antialiasing.
Is there anything to be done in the kernel to improve the image quality?
    class imageTextureX :public textureX {
public:
    __device__ imageTextureX(uint32_t width, uint32_t height, cudaTextureObject_t textureObject) :_width(width), _height(height), _textureObj(textureObject) {}
    __forceinline__ __device__  vec3 value(float u, float v, const vec3&amp; p) const override {
        //Flip Y-Coordinate;
        v = 1.0f - v;
        //De-normalize coordinate(s)
        uint32_t X = u * _width;
        //Re-normalize
        constexpr float pixelOffset{ 0.5f };
        const float denominator = 1.0f / (float)(3 * _width);
        u = (float)(3 * X + pixelOffset);

        vec3 colorVal;
        colorVal.e[0] = (float)tex2D&lt;uint8_t&gt;(_textureObj, u++ * denominator, v);
        colorVal.e[1] = (float)tex2D&lt;uint8_t&gt;(_textureObj, u++ * denominator, v);
        colorVal.e[2] = (float)tex2D&lt;uint8_t&gt;(_textureObj, u * denominator, v);
        return colorVal / 255.0f;
    }
private:
    cudaTextureObject_t _textureObj;
    uint32_t _width;
    uint32_t _height;
};

Texture definition code
//Load Texture Image from Disk
    cudaArray* cuArray;
    cudaTextureObject_t textureObject;
    int32_t textureWidth, textureHeight;
    {
        Timer tim(&quot;Prepare Image Texture&quot;);
        const static uint32_t bytesPerPixel{ 3u };
        uint8_t* pHostData;
        uint32_t bytesPerScanline;
        cudaChannelFormatDesc channelFormatDesc;
        cudaResourceDesc  resourceDesc{};
        cudaTextureDesc textureDesc{};
        int32_t componentsPerPixel = bytesPerPixel;
        pHostData = stbi_load(textureFilename.c_str(), &amp;textureWidth, &amp;textureHeight, &amp;componentsPerPixel, componentsPerPixel);
        if (nullptr == pHostData) {
            std::cerr &lt;&lt; &quot;ERROR: Could not load texture image file '&quot; &lt;&lt; textureFilename &lt;&lt; std::endl;
            return;
        }
        bytesPerScanline = bytesPerPixel * textureWidth;

        channelFormatDesc = cudaCreateChannelDesc(8, 0, 0, 0, cudaChannelFormatKindUnsigned);
        checkCudaErrors(cudaMallocArray(&amp;cuArray, &amp;channelFormatDesc, bytesPerScanline, textureHeight));
        checkCudaErrors(cudaMemcpyToArray(cuArray, 0, 0, pHostData, bytesPerScanline * textureHeight * sizeof(uint8_t), cudaMemcpyHostToDevice));
        
        resourceDesc.resType = cudaResourceTypeArray;
        resourceDesc.res.array.array = cuArray;

        textureDesc.normalizedCoords = true;
        textureDesc.filterMode = cudaFilterModePoint;
        textureDesc.addressMode[0] = cudaAddressModeWrap;
        textureDesc.addressMode[1] = cudaAddressModeWrap;
        textureDesc.readMode = cudaReadModeElementType;
        checkCudaErrors(cudaCreateTextureObject(&amp;textureObject, &amp;resourceDesc, &amp;textureDesc, nullptr));
        STBI_FREE(pHostData);
    }

The output images were ppm and converted to pgm for upload purposes
If you look closely at the edge of the sphere, in the first image it is sharp, and in the second image it's blurry, blending into the background color. This suggests to me that it's not the texture, but the ray distribution on the image plane that's the issue. The second image might be distributing rays over a larger area per pixel, for instance by using a wider AA filter, or a wider lens aperture (defocus blur).