DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/output/output_tools_xbrz.cpp
00001 #include <stdlib.h>
00002 #include <assert.h>
00003 #include <math.h>
00004 
00005 #include "dosbox.h"
00006 #include "sdlmain.h"
00007 
00008 using namespace std;
00009 
00010 #if C_XBRZ
00011 
00012 struct SDL_xBRZ sdl_xbrz;
00013 
00014 void xBRZ_Initialize()
00015 {
00016     memset(&sdl_xbrz, 0, sizeof(sdl_xbrz));
00017 
00018     Section_prop* section = static_cast<Section_prop *>(control->GetSection("render"));
00019 
00020     LOG(LOG_MISC, LOG_DEBUG)("Early init (renderer): xBRZ options");
00021 
00022     // set some defaults
00023     sdl_xbrz.task_granularity = 16;
00024     sdl_xbrz.max_scale_factor = xbrz::SCALE_FACTOR_MAX;
00025 
00026     // read options related to xBRZ here
00027     Prop_multival* prop = section->Get_multival("scaler");
00028     std::string scaler = prop->GetSection()->Get_string("type");
00029     sdl_xbrz.enable = ((scaler == "xbrz") || (scaler == "xbrz_bilinear"));
00030     sdl_xbrz.postscale_bilinear = (scaler == "xbrz_bilinear");
00031     xBRZ_Change_Options(section);
00032 }
00033 
00034 void xBRZ_Change_Options(Section_prop* section)
00035 {
00036     sdl_xbrz.task_granularity = section->Get_int("xbrz slice");
00037     sdl_xbrz.fixed_scale_factor = section->Get_int("xbrz fixed scale factor");
00038     sdl_xbrz.max_scale_factor = section->Get_int("xbrz max scale factor");
00039     if ((sdl_xbrz.max_scale_factor < 2) || (sdl_xbrz.max_scale_factor > xbrz::SCALE_FACTOR_MAX))
00040         sdl_xbrz.max_scale_factor = xbrz::SCALE_FACTOR_MAX;
00041     if ((sdl_xbrz.fixed_scale_factor < 2) || (sdl_xbrz.fixed_scale_factor > xbrz::SCALE_FACTOR_MAX))
00042         sdl_xbrz.fixed_scale_factor = 0;
00043 }
00044 
00045 // returns true if scaling possible/enabled, false otherwise
00046 bool xBRZ_SetScaleParameters(int srcWidth, int srcHeight, int dstWidth, int dstHeight)
00047 {
00048     sdl_xbrz.scale_factor = (sdl_xbrz.fixed_scale_factor == 0) ?
00049         static_cast<int>(std::sqrt((double)dstWidth * dstHeight / (srcWidth * srcHeight)) + 0.5) :
00050         sdl_xbrz.fixed_scale_factor;
00051 
00052     // enable minimal scaling if upscale is still possible but requires post-downscale
00053     // having aspect ratio correction on always implies enabled scaler because it gives better quality than DOSBox own method
00054     if (sdl_xbrz.scale_factor == 1 && (render.aspect || dstWidth > srcWidth || dstHeight > srcHeight))
00055         sdl_xbrz.scale_factor = 2;
00056 
00057     if (sdl_xbrz.scale_factor >= 2)
00058     {
00059         // ok to scale, now clamp scale factor if corresponding max option is set
00060         sdl_xbrz.scale_factor = min(sdl_xbrz.scale_factor, sdl_xbrz.max_scale_factor);
00061         sdl_xbrz.scale_on = true;
00062     }
00063     else
00064     {
00065         // scaling impossible
00066         sdl_xbrz.scale_on = false;
00067     }
00068 
00069     return sdl_xbrz.scale_on;
00070 }
00071 
00072 void xBRZ_Render(const uint32_t* renderBuf, uint32_t* xbrzBuf, const Bit16u *changedLines, const int srcWidth, const int srcHeight, int scalingFactor)
00073 {
00074 #ifdef XBRZ_PPL
00075     if (changedLines) // perf: in worst case similar to full input scaling
00076     {
00077         concurrency::task_group tg; // perf: task_group is slightly faster than pure parallel_for
00078 
00079         int yLast = 0;
00080         Bitu y = 0, index = 0;
00081         while (y < sdl.draw.height)
00082         {
00083             if (!(index & 1))
00084                 y += changedLines[index];
00085             else
00086             {
00087                 const int sliceFirst = y;
00088                 const int sliceLast = y + changedLines[index];
00089                 y += changedLines[index];
00090 
00091                 int yFirst = max(yLast, sliceFirst - 2); // we need to update two adjacent lines as well since they are analyzed by xBRZ!
00092                 yLast = min(srcHeight, sliceLast + 2);   // (and make sure to not overlap with last slice!)
00093                 for (int i = yFirst; i < yLast; i += sdl_xbrz.task_granularity)
00094                 {
00095                     tg.run([=] { 
00096                         const int iLast = min(i + sdl_xbrz.task_granularity, yLast);
00097                         xbrz::scale(scalingFactor, renderBuf, xbrzBuf, srcWidth, srcHeight, xbrz::ColorFormat::RGB, xbrz::ScalerCfg(), i, iLast);
00098                     });
00099                 }
00100             }
00101             index++;
00102         }
00103         tg.wait();
00104     }
00105     else // process complete input image
00106     {
00107         concurrency::task_group tg;
00108         for (int i = 0; i < srcHeight; i += sdl_xbrz.task_granularity)
00109         {
00110             tg.run([=] { 
00111                 const int iLast = min(i + sdl_xbrz.task_granularity, srcHeight);
00112                 xbrz::scale(scalingFactor, renderBuf, xbrzBuf, srcWidth, srcHeight, xbrz::ColorFormat::RGB, xbrz::ScalerCfg(), i, iLast);
00113             });
00114         }
00115         tg.wait();
00116     }
00117 #else
00118     /* non-PPL for non-Windows.
00119     * combine the code above, cleanly, if possible. */
00120     if (changedLines)
00121     {
00122         int yLast = 0;
00123         Bitu y = 0, index = 0;
00124         while (y < sdl.draw.height)
00125         {
00126             if (!(index & 1))
00127                 y += changedLines[index];
00128             else
00129             {
00130                 const int sliceFirst = y;
00131                 const int sliceLast = y + changedLines[index];
00132                 y += changedLines[index];
00133 
00134                 int yFirst = max(yLast, sliceFirst - 2); // we need to update two adjacent lines as well since they are analyzed by xBRZ!
00135                 yLast = min(srcHeight, sliceLast + 2);  // (and make sure to not overlap with last slice!)
00136                 xbrz::scale(scalingFactor, renderBuf, xbrzBuf, srcWidth, srcHeight, xbrz::ColorFormat::RGB, xbrz::ScalerCfg(), yFirst, yLast);
00137             }
00138             index++;
00139         }
00140     }
00141     else // process complete input image
00142     {
00143         xbrz::scale(scalingFactor, renderBuf, xbrzBuf, srcWidth, srcHeight, xbrz::ColorFormat::RGB, xbrz::ScalerCfg(), 0, srcHeight);
00144     }
00145 #endif /*XBRZ_PPL*/
00146 }
00147 
00148 #endif /*C_XBRZ*/
00149 
00150 #if C_XBRZ || C_SURFACE_POSTRENDER_ASPECT
00151 
00152 void xBRZ_PostScale(const uint32_t* src, const int srcWidth, const int srcHeight, const int srcPitch, 
00153                     uint32_t* tgt, const int tgtWidth, const int tgtHeight, const int tgtPitch, 
00154                     const bool bilinear, const int task_granularity)
00155 {
00156 # if defined(XBRZ_PPL)
00157     if (bilinear) {
00158         concurrency::task_group tg;
00159         for (int i = 0; i < tgtHeight; i += task_granularity)
00160             tg.run([=] {
00161                 const int iLast = min(i + task_granularity, tgtHeight);
00162                 xbrz::bilinearScale(&src[0], srcWidth, srcHeight, srcPitch, &tgt[0], tgtWidth, tgtHeight, tgtPitch, i, iLast, [](uint32_t pix) { return pix; });  
00163             });
00164         tg.wait();
00165     }
00166     else
00167     {
00168         concurrency::task_group tg;
00169         for (int i = 0; i < tgtHeight; i += task_granularity)
00170             tg.run([=] {
00171                 const int iLast = min(i + task_granularity, tgtHeight);
00172                 // perf: going over target is by factor 4 faster than going over source for similar image sizes
00173                 xbrz::nearestNeighborScale(&src[0], srcWidth, srcHeight, srcPitch, &tgt[0], tgtWidth, tgtHeight, tgtPitch, i, iLast, [](uint32_t pix) { return pix; });
00174             });
00175         tg.wait();
00176     }
00177 #else
00178     if (bilinear)
00179         xbrz::bilinearScale(&src[0], srcWidth, srcHeight, srcPitch, &tgt[0], tgtWidth, tgtHeight, tgtPitch, 0, tgtHeight, [](uint32_t pix) { return pix; });
00180     else
00181         xbrz::nearestNeighborScale(&src[0], srcWidth, srcHeight, srcPitch, &tgt[0], tgtWidth, tgtHeight, tgtPitch, 0, tgtHeight, [](uint32_t pix) { return pix; });
00182 #endif
00183 }
00184 
00185 #endif /*C_XBRZ || C_SURFACE_POSTRENDER_ASPECT*/