Subversion Repository Public Repository

Divide-Framework

This repository has no backups
This repository's network speed is throttled to 100KB/sec

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
#include "Headers/Texture.h"

#include "Core/Headers/TaskPool.h"
#include "Core/Headers/ParamHandler.h"
#include "Platform/Video/Headers/GFXDevice.h"

namespace Divide {

namespace {
    static const U16 g_partitionSize = 128;
};

Texture::Texture(GFXDevice& context,
                 const stringImpl& name,
                 const stringImpl& resourceLocation,
                 TextureType type,
                 bool asyncLoad)
    : GraphicsResource(context),
      Resource(ResourceType::GPU_OBJECT, name, resourceLocation),
      _numLayers(1),
      _lockMipMaps(false),
      _samplerDirty(true),
      _mipMapsDirty(true),
      _hasTransparency(false),
      _asyncLoad(asyncLoad)
{
    _width = _height = 0;
    _mipMaxLevel = _mipMinLevel = 0;
    _textureData._textureType = type;
    _textureData._samplerHash = _descriptor._samplerDescriptor.getHash();
}

Texture::~Texture()
{
}

bool Texture::load() {
    _context.loadInContext(_asyncLoad ? CurrentContext::GFX_LOADING_CTX
                                      : CurrentContext::GFX_RENDERING_CTX,
        [&](const std::atomic_bool& stopRequested) {
            threadedLoad();
        }
    );

    return true;
}

/// Load texture data using the specified file name
void Texture::threadedLoad() {
    // Make sure we have a valid file path
    if (!getResourceLocation().empty() && getResourceLocation().compare("default") != 0) {

        TextureLoadInfo info;
        info._type = _textureData._textureType;

        // Each texture face/layer must be in a comma separated list
        stringstreamImpl textureLocationList(getResourceLocation());
        // We loop over every texture in the above list and store it in this
        // temporary string
        stringImpl currentTexture;
        while (std::getline(textureLocationList, currentTexture, ',')) {
            // Skip invalid entries
            if (!currentTexture.empty()) {
                   // Attempt to load the current entry
                    if (!loadFile(info, currentTexture)) {
                        // Invalid texture files are not handled yet, so stop loading
                        return;
                    }
                    info._layerIndex++;
                    if (info._type == TextureType::TEXTURE_CUBE_ARRAY) {
                        if (info._layerIndex == 6) {
                            info._layerIndex = 0;
                            info._cubeMapCount++;
                        }
                    }
            }
        }

        if (info._type == TextureType::TEXTURE_CUBE_MAP ||
            info._type == TextureType::TEXTURE_CUBE_ARRAY) {
            if (info._layerIndex != 6) {
                Console::errorfn(
                    Locale::get(_ID("ERROR_TEXTURE_LOADER_CUBMAP_INIT_COUNT")),
                    getResourceLocation().c_str());
                return;
            }
        }

        if (info._type == TextureType::TEXTURE_2D_ARRAY ||
            info._type == TextureType::TEXTURE_2D_ARRAY_MS) {
            if (info._layerIndex != _numLayers) {
                Console::errorfn(
                    Locale::get(_ID("ERROR_TEXTURE_LOADER_ARRAY_INIT_COUNT")),
                    getResourceLocation().c_str());
                return;
            }
        }

        if (info._type == TextureType::TEXTURE_CUBE_ARRAY) {
            if (info._cubeMapCount != _numLayers) {
                Console::errorfn(
                    Locale::get(_ID("ERROR_TEXTURE_LOADER_ARRAY_INIT_COUNT")),
                    getResourceLocation().c_str());
                return;
            }
        }
    }

    Resource::load();
}

bool Texture::loadFile(const TextureLoadInfo& info, const stringImpl& name) {
    // Create a new imageData object
    ImageTools::ImageData img;
    // Flip image if needed
    img.flip(true);
    // Save file contents in  the "img" object
    ImageTools::ImageDataInterface::CreateImageData(name, img);

    // Validate data
    if (!img.data()) {
        Console::errorfn(Locale::get(_ID("ERROR_TEXTURE_LOAD")), name.c_str());
        // Missing texture fallback.
        ParamHandler& par = ParamHandler::instance();
        img.flip(false);
        // missing_texture.jpg must be something that really stands out
        ImageTools::ImageDataInterface::CreateImageData(
            par.getParam<stringImpl>(_ID("assetsLocation"), "assets") + "/" +
            par.getParam<stringImpl>(_ID("defaultTextureLocation"), "textures") +
            "/" + "missing_texture.jpg", img);
    }
    
    // Extract width, height and bitdepth
    U16 width = img.dimensions().width;
    U16 height = img.dimensions().height;
    // If we have an alpha channel, we must check for translucency
    if (img.alpha()) {

        // Each pixel is independent so this is a brilliant place to parallelize work
        // should this be atomic? At most, we run an extra task -Ionut
        std::atomic_bool abort = false;

        auto findAlpha = [&abort, &img, height](const std::atomic_bool& stopRequested, U16 start, U16 end) {
            U8 tempR, tempG, tempB, tempA;
            for (U16 i = start; i < end; ++i) {
                for (I32 j = 0; j < height; ++j) {
                    if (!abort) {
                        img.getColour(i, j, tempR, tempG, tempB, tempA);
                        if (tempA < 250) {
                            abort = true;
                        }
                    }
                }
                if (stopRequested) {
                    break;
                }
            }
        };

        parallel_for(findAlpha, width, g_partitionSize);

        _hasTransparency = abort;
    }

    Console::d_printfn(Locale::get(_ID("TEXTURE_HAS_TRANSPARENCY")),
                       name.c_str(),
                       _hasTransparency ? "yes" : "no");

    // Create a new Rendering API-dependent texture object
    _descriptor._type = info._type;
    _descriptor._internalFormat = GFXImageFormat::RGB8;
    // Select the proper colour space internal format
    bool srgb = _descriptor._samplerDescriptor.srgb();
    // We only support 8 bit per pixel, 1/2/3/4 channel textures
    switch (img.format()) {
        case GFXImageFormat::LUMINANCE:
            _descriptor._internalFormat = GFXImageFormat::LUMINANCE;
            break;
        case GFXImageFormat::RED:
            _descriptor._internalFormat = GFXImageFormat::RED8;
            break;
        case GFXImageFormat::RG:
            _descriptor._internalFormat = GFXImageFormat::RG8;
            break;
        case GFXImageFormat::BGR:
        case GFXImageFormat::RGB:
            _descriptor._internalFormat =
                srgb ? GFXImageFormat::SRGB8 : 
                       GFXImageFormat::RGB8;
            break;
        case GFXImageFormat::BGRA:
        case GFXImageFormat::RGBA:
            _descriptor._internalFormat =
                srgb ? GFXImageFormat::SRGBA8 : 
                       GFXImageFormat::RGBA8;
            break;
        case GFXImageFormat::COMPRESSED_RGB_DXT1: {
            _descriptor._internalFormat = 
                srgb ? GFXImageFormat::COMPRESSED_SRGB_DXT1 :
                       GFXImageFormat::COMPRESSED_RGB_DXT1;
            _descriptor._compressed = true;
        } break;
        case GFXImageFormat::COMPRESSED_RGBA_DXT1: {
            _descriptor._internalFormat =
                srgb ? GFXImageFormat::COMPRESSED_SRGB_ALPHA_DXT1 :
                       GFXImageFormat::COMPRESSED_RGBA_DXT1;
            _descriptor._compressed = true;
        } break;
        case GFXImageFormat::COMPRESSED_RGBA_DXT3: {
            _descriptor._internalFormat =
                srgb ? GFXImageFormat::COMPRESSED_SRGB_ALPHA_DXT3 :
                       GFXImageFormat::COMPRESSED_RGBA_DXT3;
            _descriptor._compressed = true;
        } break;
        case GFXImageFormat::COMPRESSED_RGBA_DXT5: {
            _descriptor._internalFormat =
                srgb ? GFXImageFormat::COMPRESSED_SRGB_ALPHA_DXT5 :
                       GFXImageFormat::COMPRESSED_RGBA_DXT5;
            _descriptor._compressed = true;
        } break;
    }

    U16 mipMaxLevel = to_ushort(img.mipCount());
    
    if (!_descriptor._compressed) {
        if (_descriptor._samplerDescriptor.generateMipMaps() && mipMaxLevel <= 1) {
            mipMaxLevel = to_ushort(floorf(log2f(fmaxf(width, height))));
        }
         
        mipMaxLevel += 1;
    }
    // Uploading to the GPU dependents on the rendering API
    loadData(info,
             _descriptor,
             img.imageLayers(),
             vec2<U16>(0, mipMaxLevel));

    // We will always return true because we load the "missing_texture.jpg" in case of errors
    return true;
}
};

Commits for Divide-Framework/trunk/Source Code/Platform/Video/Textures/Texture.cpp

Diff revisions: vs.
Revision Author Commited Message
788 Diff Diff IonutCava picture IonutCava Fri 21 Oct, 2016 16:11:37 +0000

[IonutCava]
- Added support for the Arena Allocator by Mamasha Knows (http://www.codeproject.com/Articles/44850/Arena-Allocator-DTOR-and-Embedded-Preallocated-Buf)
— Used for GFX Related objects: Textures, shaders, etc

759 Diff Diff IonutCava picture IonutCava Sun 07 Aug, 2016 18:34:32 +0000

[IonutCava]
- Add workaround for singlethreaded texture loading
- Small corrections to ImageTools image loading

758 Diff Diff IonutCava picture IonutCava Tue 02 Aug, 2016 16:05:09 +0000

[IonutCava]
- Added a cross platform method of naming threads (helps with debugging)
- Reduced dependency on VAR.dvd_drawID in shaders.
- Work on Single/Multi thread toggle for GFX resource loading (crashes, bugs, etc)
- Fix a bug in TaskPool where task states were never actually updated properly
- Change threadpool implementation to use std::thread instead of boost::thread

721 Diff Diff IonutCava picture IonutCava Wed 08 Jun, 2016 15:47:49 +0000

[IonutCava]
- Spelling: change all references from our code of “color” to the PROPER British version of “colour” because it sounds 100x better

714 Diff Diff IonutCava picture IonutCava Thu 26 May, 2016 16:26:23 +0000

[IonutCava]
- Initial code for multithreaded scene load:
— Tasks can have a “sync with gpu” flag that will cause them to use a shared context (so they can call GL functions)
- Added per scene GUI lists that get passed to the main GUI class (still need a base class to hold the map and accessors to avoid code duplication)
- Re-enabled threading unit tests

692 Diff Diff IonutCava picture IonutCava Wed 27 Apr, 2016 16:24:26 +0000

[IonutCava]
- Resource system cleanup:
— Resource name and resource file location (if any) is now passed only via explicit constructors! (ResourceDescriptors already contain this data, so why use setters?)
- Fix a bug with ortho projection matrix calculation (set m[3][3] to 1. this was skipped when the identity() call was changed to zero() in the ortho() function)
— This also fixed text rendering

675 Diff Diff IonutCava picture IonutCava Tue 12 Apr, 2016 14:23:59 +0000

[IonutCava]
- Create a “reflection target pool” that reflective nodes can use instead of having a reflection render target per node
- Update particles at fixed time intervals instead of each update loop. 33ms for now (30FPS) seems like a decent balance.
- Add a “parallel_for” call that uses the task pool, a function to call, a total count and a partition size
- Frustum culling does not create a new task per node, instead the partition size is now customizable with the new parallel_for system

671 Diff Diff IonutCava picture IonutCava Fri 08 Apr, 2016 16:26:49 +0000

[Ionut]
- Custom memory allocation system part 1:
— Add http://www.codeproject.com/Articles/1089905/A-Custom-STL-std-allocator-Replacement-Improves-Pe
— Add custom allocators to strings and vectors
— Add custom allocators to a few test classes
— No support for aligned memory yet, so vec4<F32> and mat4<F32> vectors use the old allocation system
- Replace more std::async call with our custom task system

670 Diff Diff IonutCava picture IonutCava Wed 06 Apr, 2016 16:21:35 +0000

[IonutCava]
- getInstance() renamed to instance() for simplicity (should really go away altogether, but that’s a different issue)
- some particle emitter threading updates

669 IonutCava picture IonutCava Mon 04 Apr, 2016 16:15:35 +0000

[IonutCava]
- Move Task creation calls to TaskPool.h
- Allow tasks to use any pool, but default behaviour is to use the Kernel’s main task pool
- Change image transparency check to use the task pool instead of OpenMP
— Perfect place for future parallel_for implementation
- Warning fixes
- Some method renaming for improved readability