[AD] WIP compressed texture support patch

[ Thread Index | Date Index | More lists.liballeg.org/allegro-developers Archives ]


My new employer makes it a bit difficult for me to OSS projects (typically, each patch of mine needs to be cleared, which adds a day or so of lag), so I decided to get this very WIP (please don't merge this!) patch for compressed texture support some review.

The general idea behind compressed textures is that they allow 6x to 4x compression ratios on the GPU with reasonable quality for smooth images (doubt it works well for pixel art). If your game has a lot of art assets, this would make it easier to fit it all in VRAM. This patch implements the DXT1, DXT3 and DXT5 compression formats (see https://en.wikipedia.org/wiki/S3_Texture_Compression for a quick introduction).

Conceptually, ALLEGRO_BITMAPs (just 'bitmaps' from now on) act very much like read only (i.e. FBO-less) bitmaps, both in terms of user UI (i.e. drawing into them requires falling back to memory drawing) and backing code (a lot of the FBO-less code is re-used). The key difference is that you cannot create compressed memory bitmaps. This has nothing to do with the algorithms per se (they are trivial), but rather with the fact that they are patented. It seems to me (IANAL) that it's fine to use compressed textures in Allegro, as long as compression and decompression is done by the drivers (those drivers thus deal with the licensing). This is, in fact, what this patch does.

Bitmap locking is a bit different with compressed bitmaps. You can lock a compressed bitmap in a non-locked format (i.e. compression/decompressing it depending on what flags you use), but you cannot lock in a compressed format. This is for two reasons. First, the drivers don't support compressing a non-compressed video bitmap. Second, the memory layout of these compressed bitmaps is very different from the memory layout of the usual non-compressed bitmaps, so re-using the API just wouldn't work.

Instead, I introduced two new locking functions that lock using block coordinates. E.g. consider:

ALLEGRO_LOCKED_REGION* al_lock_bitmap_region_blocked(ALLEGRO_BITMAP *bitmap, int x_block, int y_block, int width_block, int height_block, int flags)

Calling that function like so:

al_lock_bitmap_region_blocked(bmp, 1, 1, 1, 1, flags);

is roughly identical to:

int format = al_get_bitmap_format(bmp);
int bw = al_get_pixel_block_width(format)
al_lock_bitmap_region(bmp, bw, bw, bw, bw, format, flags);

Couple of things to note. These blocked locking functions do not support format conversion: this simplifies the code quite a bit. These functions return a 'regular' ALLEGRO_LOCKED_REGION that works roughly the same way. The only difference is that rows in the locked memory are composed of blocks.

These blocked locking functions are useful for a few reasons. First, it simplifies bitmap cloning (otherwise cloning a compressed bitmap would involve decompressing and re-compressing it). Second, it allows the user to perhaps create compressed bitmap atlasses. Third, although you can compress bitmaps using al_lock_bitmap, the quality of compression is variable between drivers. Thus, it is best to compress beforehand and then load compressed textures directly. A common format for this is the DirectX DDS file, so I wrote a simple loader for it (it works for OpenGL too).

So that's the overview of the good parts. The ugly part of this patch is that, as you all know, we store OpenGL bitmaps upside down. This means that during blocked locking of compressed OpenGL bitmaps I need to flip the pixels within the locked blocks (luckily, the compression format is simple, so this is easy to do). We should give a little bit of thought about this and see if we want find a different solution to this (perhaps using texture coordinate matrices). I don't think this is a practical issue (the code to deal with this is already there and it works), or that it needs to be solved now, but it may be neater to avoid this issue entirely. With this talk about 5.2, it'd be nice not to write ourselves into a corner with this question... I think it might be as simple as simply removing the al_use_tex_matrix from shaders or w/e its called and making the use of the texture matrix mandatory.

Another issue is that compression/decompression on Windows requires the D3DX library. I made it a hard requirement for this feature (it still loads the necessary function dynamically though).

Anyway, I'd prefer if somebody looked over all this and checked if anything looks crazy. Don't worry about the formatting, etc, I'll fix it later. I'll also write documentation and tests. Also, I don't know if this works at all on Android/iOS/OSX, so it'd be nice if this was tested too (at least to see if it compiles). I only implemented DXT1/3/5 formats, but there are others... if the ones I implemented don't work, then perhaps some others will. The framework should be good enough to handle them (although the OpenGL flipping bit will need to be implemented for them).

The patch is attached, and you can also look at this: https://github.com/SiegeLord/allegro5/compare/compression .

Thanks,

-SL
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 140da63..eb8c5f7 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -692,6 +692,7 @@ if(WIN32)
         find_package(D3DX9)
         if(D3DX9_FOUND)
             include_directories(BEFORE SYSTEM ${D3DX9_INCLUDE_DIR})
+            set(ALLEGRO_CFG_D3DX9 1)
         endif(D3DX9_FOUND)
    endif(SUPPORT_D3D)
 
diff --git a/addons/image/CMakeLists.txt b/addons/image/CMakeLists.txt
index ef0eb73..50f3120 100644
--- a/addons/image/CMakeLists.txt
+++ b/addons/image/CMakeLists.txt
@@ -1,6 +1,6 @@
 option(WANT_NATIVE_IMAGE_LOADER "Enable the native platform image loader (if available)" on)
 
-set(IMAGE_SOURCES bmp.c iio.c pcx.c tga.c)
+set(IMAGE_SOURCES bmp.c iio.c pcx.c tga.c dds.c)
 set(IMAGE_INCLUDE_FILES allegro5/allegro_image.h)
 
 set_our_header_properties(${IMAGE_INCLUDE_FILES})
diff --git a/addons/image/allegro5/internal/aintern_image.h b/addons/image/allegro5/internal/aintern_image.h
index 5fd665f..7902cc7 100644
--- a/addons/image/allegro5/internal/aintern_image.h
+++ b/addons/image/allegro5/internal/aintern_image.h
@@ -37,6 +37,9 @@ ALLEGRO_IIO_FUNC(bool, _al_save_tga, (const char *filename, ALLEGRO_BITMAP *bmp)
 ALLEGRO_IIO_FUNC(ALLEGRO_BITMAP *, _al_load_tga_f, (ALLEGRO_FILE *f, int flags));
 ALLEGRO_IIO_FUNC(bool, _al_save_tga_f, (ALLEGRO_FILE *f, ALLEGRO_BITMAP *bmp));
 
+ALLEGRO_IIO_FUNC(ALLEGRO_BITMAP *, _al_load_dds, (const char *filename, int flags));
+ALLEGRO_IIO_FUNC(ALLEGRO_BITMAP *, _al_load_dds_f, (ALLEGRO_FILE *f, int flags));
+
 #ifdef ALLEGRO_CFG_IIO_HAVE_GDIPLUS
 ALLEGRO_IIO_FUNC(bool, _al_init_gdiplus, (void));
 ALLEGRO_IIO_FUNC(void, _al_shutdown_gdiplus, (void));
diff --git a/addons/image/dds.c b/addons/image/dds.c
new file mode 100644
index 0000000..bb239be
--- /dev/null
+++ b/addons/image/dds.c
@@ -0,0 +1,168 @@
+/*         ______   ___    ___
+ *        /\  _  \ /\_ \  /\_ \
+ *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
+ *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
+ *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
+ *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
+ *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
+ *                                           /\____/
+ *                                           \_/__/
+ *
+ *      A simple DDS reader.
+ *
+ *      See readme.txt for copyright information.
+ */
+
+#include "allegro5/allegro.h"
+#include "allegro5/allegro_image.h"
+#include "allegro5/internal/aintern_image.h"
+
+#include "iio.h"
+
+ALLEGRO_DEBUG_CHANNEL("image")
+
+typedef int DWORD;
+
+typedef struct {
+   DWORD dwSize;
+   DWORD dwFlags;
+   DWORD dwFourCC;
+   DWORD dwRGBBitCount;
+   DWORD dwRBitMask;
+   DWORD dwGBitMask;
+   DWORD dwBBitMask;
+   DWORD dwABitMask;
+} DDS_PIXELFORMAT;
+
+typedef struct {
+   DWORD           dwSize;
+   DWORD           dwFlags;
+   DWORD           dwHeight;
+   DWORD           dwWidth;
+   DWORD           dwPitchOrLinearSize;
+   DWORD           dwDepth;
+   DWORD           dwMipMapCount;
+   DWORD           dwReserved1[11];
+   DDS_PIXELFORMAT ddspf;
+   DWORD           dwCaps;
+   DWORD           dwCaps2;
+   DWORD           dwCaps3;
+   DWORD           dwCaps4;
+   DWORD           dwReserved2;
+} DDS_HEADER;
+
+#define DDS_HEADER_SIZE 124
+#define DDS_PIXELFORMAT_SIZE 32
+
+#define FOURCC(c0, c1, c2, c3) ((int)(c0) | ((int)(c1) << 8) | ((int)(c2) << 16) | ((int)(c3) << 24))
+
+#define DDPF_FOURCC 0x4
+
+ALLEGRO_BITMAP *_al_load_dds_f(ALLEGRO_FILE *f, int flags)
+{
+   ALLEGRO_BITMAP *bmp;
+   DDS_HEADER header;
+   DWORD magic;
+   size_t num_read;
+   int w, h, fourcc, format, block_width, block_size;
+   ALLEGRO_STATE state;
+   ALLEGRO_LOCKED_REGION *lr;
+   int ii;
+   char* ptr;
+   (void)flags;
+
+   magic = al_fread32le(f);
+   if (magic != 0x20534444) {
+      ALLEGRO_ERROR("Invalid DDS magic number.\n");
+      return NULL;
+   }
+
+   num_read = al_fread(f, &header, sizeof(DDS_HEADER));
+   if (num_read != DDS_HEADER_SIZE) {
+      ALLEGRO_ERROR("Wrong DDS header size. Got %d, expected %d.\n",
+         num_read, DDS_HEADER_SIZE);
+      return NULL;
+   }
+
+   if (!(header.ddspf.dwFlags & DDPF_FOURCC)) {
+      ALLEGRO_ERROR("Only compressed DDS formats supported.\n");
+      return NULL;
+   }
+
+   w = header.dwWidth;
+   h = header.dwHeight;
+   fourcc = header.ddspf.dwFourCC;
+
+   switch (fourcc) {
+      case FOURCC('D', 'X', 'T', '1'):
+         format = ALLEGRO_PIXEL_FORMAT_RGBA_DXT1;
+         break;
+      case FOURCC('D', 'X', 'T', '3'):
+         format = ALLEGRO_PIXEL_FORMAT_RGBA_DXT3;
+         break;
+      case FOURCC('D', 'X', 'T', '5'):
+         format = ALLEGRO_PIXEL_FORMAT_RGBA_DXT5;
+         break;
+      default:
+         ALLEGRO_ERROR("Invalid pixel format.\n");
+         return NULL;
+   }
+
+   block_width = al_get_pixel_block_width(format);
+   block_size = al_get_pixel_block_size(format);
+
+   al_store_state(&state, ALLEGRO_STATE_NEW_BITMAP_PARAMETERS);
+   al_set_new_bitmap_flags(ALLEGRO_VIDEO_BITMAP);
+   al_set_new_bitmap_format(format);
+   bmp = al_create_bitmap(w, h);
+   if (!bmp) {
+      ALLEGRO_ERROR("Couldn't create bitmap.\n");
+      goto FAIL;
+   }
+
+   if (al_get_bitmap_format(bmp) != format) {
+      ALLEGRO_ERROR("Created a bad bitmap.\n");
+      goto FAIL;
+   }
+
+   lr = al_lock_bitmap_blocked(bmp, ALLEGRO_LOCK_WRITEONLY);
+   ptr = lr->data;
+
+   for (ii = 0; ii < h / block_width; ii++) {
+      size_t pitch = (size_t)(w / block_width * block_size);
+      num_read = al_fread(f, ptr, pitch);
+      if (num_read != pitch) {
+         ALLEGRO_ERROR("DDS file too short.\n");
+         goto FAIL;
+      }
+      ptr += lr->pitch;
+   }
+   al_unlock_bitmap(bmp);
+
+   goto RESET;
+FAIL:
+   if (lr)
+      al_unlock_bitmap(bmp);
+   al_destroy_bitmap(bmp);
+   bmp = NULL;
+RESET:
+   al_restore_state(&state);
+   return bmp;
+}
+
+ALLEGRO_BITMAP *_al_load_dds(const char *filename, int flags)
+{
+   ALLEGRO_FILE *f;
+   ALLEGRO_BITMAP *bmp;
+   ASSERT(filename);
+
+   f = al_fopen(filename, "rb");
+   if (!f)
+      return NULL;
+
+   bmp = _al_load_dds_f(f, flags);
+
+   al_fclose(f);
+
+   return bmp;
+}
diff --git a/addons/image/iio.c b/addons/image/iio.c
index d98716e..8cf1cdf 100644
--- a/addons/image/iio.c
+++ b/addons/image/iio.c
@@ -35,6 +35,9 @@ bool al_init_image_addon(void)
    success |= al_register_bitmap_loader_f(".tga", _al_load_tga_f);
    success |= al_register_bitmap_saver_f(".tga", _al_save_tga_f);
 
+   success |= al_register_bitmap_loader(".dds", _al_load_dds);
+   success |= al_register_bitmap_loader_f(".dds", _al_load_dds_f);
+
 /* ALLEGRO_CFG_IIO_HAVE_* is sufficient to know that the library
    should be used. i.e., ALLEGRO_CFG_IIO_HAVE_GDIPLUS and
    ALLEGRO_CFG_IIO_HAVE_PNG will never both be set. */
diff --git a/addons/primitives/line_soft.c b/addons/primitives/line_soft.c
index f5cd548..84dcd11 100644
--- a/addons/primitives/line_soft.c
+++ b/addons/primitives/line_soft.c
@@ -22,6 +22,7 @@
 #include "allegro5/allegro.h"
 #include "allegro5/allegro_primitives.h"
 #include "allegro5/internal/aintern_blend.h"
+#include "allegro5/internal/aintern_bitmap.h"
 #include "allegro5/internal/aintern_prim.h"
 #include "allegro5/internal/aintern_prim_soft.h"
 #include <math.h>
@@ -630,7 +631,8 @@ void al_draw_soft_line(ALLEGRO_VERTEX* v1, ALLEGRO_VERTEX* v2, uintptr_t state,
       min_y = clip_min_y;
 
    if (al_is_bitmap_locked(target)) {
-      if (!_al_bitmap_region_is_locked(target, min_x, min_y, max_x - min_x, max_y - min_y))
+      if (!_al_bitmap_region_is_locked(target, min_x, min_y, max_x - min_x, max_y - min_y)
+            || _al_pixel_format_is_video_only(target->locked_region.format))
          return;
    } else {
       if (!(lr = al_lock_bitmap_region(target, min_x, min_y, max_x - min_x, max_y - min_y, ALLEGRO_PIXEL_FORMAT_ANY, 0)))
diff --git a/addons/primitives/primitives.c b/addons/primitives/primitives.c
index 7ad231a..0087e88 100644
--- a/addons/primitives/primitives.c
+++ b/addons/primitives/primitives.c
@@ -22,6 +22,7 @@
 #include "allegro5/internal/aintern.h"
 #include "allegro5/internal/aintern_bitmap.h"
 #include "allegro5/internal/aintern_exitfunc.h"
+#include "allegro5/internal/aintern_pixels.h"
 #include "allegro5/internal/aintern_prim.h"
 #include "allegro5/internal/aintern_prim_directx.h"
 #include "allegro5/internal/aintern_prim_opengl.h"
@@ -82,7 +83,9 @@ int al_draw_prim(const void* vtxs, const ALLEGRO_VERTEX_DECL* decl,
     * view space should occur here
     */
    
-   if (al_get_bitmap_flags(target) & ALLEGRO_MEMORY_BITMAP || (texture && al_get_bitmap_flags(texture) & ALLEGRO_MEMORY_BITMAP)) {
+   if (al_get_bitmap_flags(target) & ALLEGRO_MEMORY_BITMAP
+         || (texture && al_get_bitmap_flags(texture) & ALLEGRO_MEMORY_BITMAP)
+         || _al_pixel_format_is_compressed(al_get_bitmap_format(target))) {
       ret =  _al_draw_prim_soft(texture, vtxs, decl, start, end, type);
    } else {
       int flags = al_get_display_flags(_al_get_bitmap_display(target));
@@ -116,7 +119,9 @@ int al_draw_indexed_prim(const void* vtxs, const ALLEGRO_VERTEX_DECL* decl,
     * view space should occur here
     */
    
-   if (al_get_bitmap_flags(target) & ALLEGRO_MEMORY_BITMAP || (texture && al_get_bitmap_flags(texture) & ALLEGRO_MEMORY_BITMAP)) {
+   if (al_get_bitmap_flags(target) & ALLEGRO_MEMORY_BITMAP
+      || (texture && al_get_bitmap_flags(texture) & ALLEGRO_MEMORY_BITMAP)
+      || _al_pixel_format_is_compressed(al_get_bitmap_format(target))) {
       ret =  _al_draw_prim_indexed_soft(texture, vtxs, decl, indices, num_vtx, type);
    } else {
       int flags = al_get_display_flags(_al_get_bitmap_display(target));
@@ -509,7 +514,9 @@ int al_draw_vertex_buffer(ALLEGRO_VERTEX_BUFFER* vertex_buffer,
 
    target = al_get_target_bitmap();
 
-   if (al_get_bitmap_flags(target) & ALLEGRO_MEMORY_BITMAP || (texture && al_get_bitmap_flags(texture) & ALLEGRO_MEMORY_BITMAP)) {
+   if (al_get_bitmap_flags(target) & ALLEGRO_MEMORY_BITMAP
+         || (texture && al_get_bitmap_flags(texture) & ALLEGRO_MEMORY_BITMAP)
+         || _al_pixel_format_is_compressed(al_get_bitmap_format(target))) {
       ret = _al_draw_buffer_common_soft(vertex_buffer, texture, NULL, start, end, type);
    } else {
       int flags = al_get_display_flags(al_get_current_display());
@@ -545,7 +552,9 @@ int al_draw_indexed_buffer(ALLEGRO_VERTEX_BUFFER* vertex_buffer,
 
    target = al_get_target_bitmap();
 
-   if (al_get_bitmap_flags(target) & ALLEGRO_MEMORY_BITMAP || (texture && al_get_bitmap_flags(texture) & ALLEGRO_MEMORY_BITMAP)) {
+   if (al_get_bitmap_flags(target) & ALLEGRO_MEMORY_BITMAP
+         || (texture && al_get_bitmap_flags(texture) & ALLEGRO_MEMORY_BITMAP)
+         || _al_pixel_format_is_compressed(al_get_bitmap_format(target))) {
       ret = _al_draw_buffer_common_soft(vertex_buffer, texture, index_buffer, start, end, type);
    } else {
       int flags = al_get_display_flags(al_get_current_display());
diff --git a/cmake/FileList.cmake b/cmake/FileList.cmake
index e3ae318..1f08664 100644
--- a/cmake/FileList.cmake
+++ b/cmake/FileList.cmake
@@ -79,6 +79,7 @@ set(ALLEGRO_SRC_D3D_FILES
     src/win/d3d_display_formats.cpp
     src/win/d3d_render_state.cpp
     src/win/d3d_shader.cpp
+    src/win/d3d_d3dx9.cpp
     )
 
 set(ALLEGRO_SRC_OPENGL_FILES
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index 9e12ddd..97171af 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -115,6 +115,7 @@ example(ex_blend_test ${PRIM})
 example(ex_blit ${FONT} ${IMAGE} ${COLOR} ${DATA_IMAGES})
 example(ex_clip ${FONT} ${COLOR})
 example(ex_color ex_color.cpp ${NIHGUI} ${TTF} ${COLOR} DATA ${DATA_TTF})
+example(ex_compressed ${IMAGE} ${FONT} ${DATA_IMAGES})
 example(ex_convert CONSOLE ${IMAGE})
 example(ex_depth_mask ${IMAGE} ${TTF} ${DATA_IMAGES} ${DATA_TTF})
 example(ex_disable_screensaver ${FONT})
diff --git a/examples/data/mysha_dxt1.dds b/examples/data/mysha_dxt1.dds
new file mode 100644
index 0000000..d632ed8
Binary files /dev/null and b/examples/data/mysha_dxt1.dds differ
diff --git a/examples/data/mysha_dxt3.dds b/examples/data/mysha_dxt3.dds
new file mode 100644
index 0000000..d8e958d
Binary files /dev/null and b/examples/data/mysha_dxt3.dds differ
diff --git a/examples/data/mysha_dxt5.dds b/examples/data/mysha_dxt5.dds
new file mode 100644
index 0000000..850a238
Binary files /dev/null and b/examples/data/mysha_dxt5.dds differ
diff --git a/examples/ex_bitmap.c b/examples/ex_bitmap.c
index b01d5d6..1355a56 100644
--- a/examples/ex_bitmap.c
+++ b/examples/ex_bitmap.c
@@ -107,7 +107,7 @@ int main(int argc, char **argv)
             
         if (redraw && al_is_event_queue_empty(queue)) {
             redraw = false;
-            al_clear_to_color(al_map_rgb_f(0, 0, 0));
+            al_clear_to_color(al_map_rgb_f(0.1, 0, 0.1));
             if (zoom == 1)
                 al_draw_bitmap(bitmap, 0, 0, 0);
             else
diff --git a/examples/ex_compressed.c b/examples/ex_compressed.c
new file mode 100644
index 0000000..6274953
--- /dev/null
+++ b/examples/ex_compressed.c
@@ -0,0 +1,193 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "allegro5/allegro.h"
+#include "allegro5/allegro_image.h"
+#include "allegro5/allegro_font.h"
+
+#include "common.c"
+
+typedef struct BITMAP_TYPE {
+    ALLEGRO_BITMAP* bmp;
+    ALLEGRO_BITMAP* clone;
+    ALLEGRO_BITMAP* decomp;
+    ALLEGRO_BITMAP* lock_clone;
+    ALLEGRO_PIXEL_FORMAT format;
+    const char* name;
+} BITMAP_TYPE;
+
+int main(int argc, char **argv)
+{
+   const char *filename;
+   ALLEGRO_DISPLAY *display;
+   ALLEGRO_TIMER *timer;
+   ALLEGRO_EVENT_QUEUE *queue;
+   ALLEGRO_FONT *font;
+   ALLEGRO_BITMAP *bkg;
+   bool redraw = true;
+   int ii;
+   int cur_bitmap = 0;
+   bool compare = false;
+   #define NUM_BITMAPS 4
+   BITMAP_TYPE bitmaps[NUM_BITMAPS] = {
+      {NULL, NULL, NULL, NULL, ALLEGRO_PIXEL_FORMAT_ANY,       "Uncompressed"},
+      {NULL, NULL, NULL, NULL, ALLEGRO_PIXEL_FORMAT_RGBA_DXT1, "DXT1"},
+      {NULL, NULL, NULL, NULL, ALLEGRO_PIXEL_FORMAT_RGBA_DXT3, "DXT3"},
+      {NULL, NULL, NULL, NULL, ALLEGRO_PIXEL_FORMAT_RGBA_DXT5, "DXT5"},
+   };
+
+   if (argc > 1) {
+      filename = argv[1];
+   }
+   else {
+      filename = "data/mysha.pcx";
+   }
+
+   if (!al_init()) {
+      abort_example("Could not init Allegro.\n");
+   }
+
+   open_log();
+    
+   if (argc > 2) {
+      al_set_new_display_adapter(atoi(argv[2]));
+   }
+
+   al_init_image_addon();
+   al_init_font_addon();
+   al_install_keyboard();
+
+   display = al_create_display(640, 480);
+   if (!display) {
+      abort_example("Error creating display\n");
+   }
+
+   for (ii = 0; ii < NUM_BITMAPS; ii++) {
+      double t0, t1;
+      al_set_new_bitmap_format(bitmaps[ii].format);
+      
+      /* Load */
+      t0 = al_get_time();
+      bitmaps[ii].bmp = al_load_bitmap(filename);
+      t1 = al_get_time();
+      
+      if (!bitmaps[ii].bmp) {
+         abort_example("%s not found or failed to load\n", filename);
+      }
+      log_printf("%s load time: %f sec\n", bitmaps[ii].name, t1 - t0);
+
+      /* Clone */
+      t0 = al_get_time();
+      bitmaps[ii].clone = al_clone_bitmap(bitmaps[ii].bmp);
+      t1 = al_get_time();
+
+      if (!bitmaps[ii].clone) {
+         abort_example("Couldn't clone %s\n", bitmaps[ii].name);
+      }
+      log_printf("%s clone time: %f sec\n", bitmaps[ii].name, t1 - t0);
+
+      /* Decompress */
+      al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_ANY);
+      t0 = al_get_time();
+      bitmaps[ii].decomp = al_clone_bitmap(bitmaps[ii].bmp);
+      t1 = al_get_time();
+
+      if (!bitmaps[ii].decomp) {
+         abort_example("Couldn't decompress %s\n", bitmaps[ii].name);
+      }
+      log_printf("%s decompress time: %f sec\n", bitmaps[ii].name, t1 - t0);
+      
+      /* RW lock */
+      al_set_new_bitmap_format(bitmaps[ii].format);
+      bitmaps[ii].lock_clone = al_clone_bitmap(bitmaps[ii].bmp);
+      
+      if (!bitmaps[ii].lock_clone) {
+         abort_example("Couldn't clone %s\n", bitmaps[ii].name);
+      }
+      
+      if (al_get_bitmap_width(bitmaps[ii].bmp) > 128
+            && al_get_bitmap_height(bitmaps[ii].bmp) > 128) {
+         int bitmap_format = al_get_bitmap_format(bitmaps[ii].bmp);
+         int block_width = al_get_pixel_block_width(bitmap_format);
+         
+         /* Lock and unlock it, hopefully causing a no-op operation */
+         al_lock_bitmap_region_blocked(bitmaps[ii].lock_clone,
+            16 / block_width, 16 / block_width, 64 / block_width,
+            64 / block_width, ALLEGRO_LOCK_READWRITE);
+         
+         al_unlock_bitmap(bitmaps[ii].lock_clone);
+      }
+   }
+
+   bkg = al_load_bitmap("data/bkg.png");
+   if (!bkg) {
+      abort_example("data/bkg.png not found or failed to load\n");
+   }
+
+   al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_ANY);
+   font = al_create_builtin_font();
+   timer = al_create_timer(1.0 / 30);
+   queue = al_create_event_queue();
+   al_register_event_source(queue, al_get_display_event_source(display));
+   al_register_event_source(queue, al_get_keyboard_event_source());
+   al_register_event_source(queue, al_get_timer_event_source(timer));
+   al_start_timer(timer);
+
+   while (1) {
+      ALLEGRO_EVENT event;
+      al_wait_for_event(queue, &event);
+      switch (event.type) {
+         case ALLEGRO_EVENT_DISPLAY_CLOSE:
+            goto EXIT;
+         case ALLEGRO_EVENT_TIMER:
+            redraw = true;
+            break;
+         case ALLEGRO_EVENT_KEY_DOWN:
+            switch (event.keyboard.keycode) {
+               case ALLEGRO_KEY_LEFT:
+                  cur_bitmap = (cur_bitmap - 1 + NUM_BITMAPS) % NUM_BITMAPS;
+                  break;
+               case ALLEGRO_KEY_RIGHT:
+                  cur_bitmap = (cur_bitmap + 1) % NUM_BITMAPS;
+                  break;
+               case ALLEGRO_KEY_SPACE:
+                  compare = true;
+                  break;
+               case ALLEGRO_KEY_ESCAPE:
+                  goto EXIT;
+            }
+            break;
+         case ALLEGRO_EVENT_KEY_UP:
+            if (event.keyboard.keycode == ALLEGRO_KEY_SPACE) {
+               compare = false;
+            }
+            break;
+      }
+      if (redraw && al_is_event_queue_empty(queue)) {
+         int w = al_get_bitmap_width(bitmaps[cur_bitmap].bmp);
+         int h = al_get_bitmap_height(bitmaps[cur_bitmap].bmp);
+         int idx = compare ? 0 : cur_bitmap;
+         redraw = false;
+         al_clear_to_color(al_map_rgb_f(0, 0, 0));
+         al_draw_bitmap(bkg, 0, 0, 0);
+         al_draw_textf(font, al_map_rgb_f(1, 1, 1), 5, 5, ALLEGRO_ALIGN_LEFT, 
+            "SPACE to compare. Arrows to switch. Format: %s", bitmaps[idx].name);
+         al_draw_bitmap(bitmaps[idx].bmp, 0, 20, 0);
+         al_draw_bitmap(bitmaps[idx].clone, w, 20, 0);
+         al_draw_bitmap(bitmaps[idx].decomp, 0, 20 + h, 0);
+         al_draw_bitmap(bitmaps[idx].lock_clone, w, 20 + h, 0);
+         al_flip_display();
+      }
+   }
+EXIT:
+
+   al_destroy_bitmap(bkg);
+   for (ii = 0; ii < NUM_BITMAPS; ii++) {
+      al_destroy_bitmap(bitmaps[ii].bmp);
+   }
+
+   close_log(false);
+
+   return 0;
+}
+
+/* vim: set sts=4 sw=4 et: */
diff --git a/include/allegro5/bitmap_lock.h b/include/allegro5/bitmap_lock.h
index a6a6eb4..ba62a20 100644
--- a/include/allegro5/bitmap_lock.h
+++ b/include/allegro5/bitmap_lock.h
@@ -26,11 +26,15 @@ struct ALLEGRO_LOCKED_REGION {
    int format;
    int pitch;
    int pixel_size;
+   int pixel_size_bits;
 };
 
 
 AL_FUNC(ALLEGRO_LOCKED_REGION*, al_lock_bitmap, (ALLEGRO_BITMAP *bitmap, int format, int flags));
 AL_FUNC(ALLEGRO_LOCKED_REGION*, al_lock_bitmap_region, (ALLEGRO_BITMAP *bitmap, int x, int y, int width, int height, int format, int flags));
+AL_FUNC(ALLEGRO_LOCKED_REGION*, al_lock_bitmap_blocked, (ALLEGRO_BITMAP *bitmap, int flags));
+AL_FUNC(ALLEGRO_LOCKED_REGION*, al_lock_bitmap_region_blocked, (ALLEGRO_BITMAP *bitmap, int x_block, int y_block,
+      int width_block, int height_block, int flags));
 AL_FUNC(void, al_unlock_bitmap, (ALLEGRO_BITMAP *bitmap));
 AL_FUNC(bool, al_is_bitmap_locked, (ALLEGRO_BITMAP *bitmap));
 
diff --git a/include/allegro5/color.h b/include/allegro5/color.h
index 3759d3a..393f094 100644
--- a/include/allegro5/color.h
+++ b/include/allegro5/color.h
@@ -50,6 +50,9 @@ typedef enum ALLEGRO_PIXEL_FORMAT
    ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE      = 25,
    ALLEGRO_PIXEL_FORMAT_RGBA_4444         = 26,
    ALLEGRO_PIXEL_FORMAT_SINGLE_CHANNEL_8  = 27,
+   ALLEGRO_PIXEL_FORMAT_RGBA_DXT1         = 28,
+   ALLEGRO_PIXEL_FORMAT_RGBA_DXT3         = 29,
+   ALLEGRO_PIXEL_FORMAT_RGBA_DXT5         = 30,
    ALLEGRO_NUM_PIXEL_FORMATS
 } ALLEGRO_PIXEL_FORMAT;
 
@@ -69,7 +72,8 @@ AL_FUNC(void, al_unmap_rgba_f, (ALLEGRO_COLOR color, float *r, float *g, float *
 /* Pixel formats */
 AL_FUNC(int, al_get_pixel_size, (int format));
 AL_FUNC(int, al_get_pixel_format_bits, (int format));
-
+AL_FUNC(int, al_get_pixel_block_size, (int format));
+AL_FUNC(int, al_get_pixel_block_width, (int format));
 
 #ifdef __cplusplus
    }
diff --git a/include/allegro5/internal/aintern.h b/include/allegro5/internal/aintern.h
index 21da560..702e171 100644
--- a/include/allegro5/internal/aintern.h
+++ b/include/allegro5/internal/aintern.h
@@ -31,6 +31,7 @@
 #define _ALLEGRO_MAX(x,y)     (((x) > (y)) ? (x) : (y))
 #define _ALLEGRO_CLAMP(x,y,z) _ALLEGRO_MAX((x), _ALLEGRO_MIN((y), (z)))
 
+int _al_get_least_multiple(int val, int mul);
 
 /* message stuff */
 #define ALLEGRO_MESSAGE_SIZE  4096
diff --git a/include/allegro5/internal/aintern_bitmap.h b/include/allegro5/internal/aintern_bitmap.h
index 4c1d7bd..853104b 100644
--- a/include/allegro5/internal/aintern_bitmap.h
+++ b/include/allegro5/internal/aintern_bitmap.h
@@ -26,6 +26,9 @@ struct ALLEGRO_BITMAP
    int _format;
    int _flags;
    ALLEGRO_DISPLAY *_display;
+   /* What format is used for the backing memory
+    * (can be different, for e.g. compressed bitmaps) */
+   int _memory_format;
 
    int w, h;
    /*
@@ -107,11 +110,15 @@ struct ALLEGRO_BITMAP_INTERFACE
    void (*destroy_bitmap)(ALLEGRO_BITMAP *bitmap);
 
    ALLEGRO_LOCKED_REGION * (*lock_region)(ALLEGRO_BITMAP *bitmap,
-   	int x, int y, int w, int h, int format,
-	int flags);
+      int x, int y, int w, int h, int format, int flags);
 
    void (*unlock_region)(ALLEGRO_BITMAP *bitmap);
 
+   ALLEGRO_LOCKED_REGION * (*lock_compressed_region)(ALLEGRO_BITMAP *bitmap,
+      int x, int y, int w, int h, int flags);
+
+   void (*unlock_compressed_region)(ALLEGRO_BITMAP *bitmap);
+
    /* Used to update any dangling pointers the bitmap driver might keep. */
    void (*bitmap_pointer_changed)(ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP *old);
 };
@@ -132,6 +139,11 @@ void _al_convert_bitmap_data(
 	int sx, int sy, int dx, int dy,
 	int width, int height);
 
+void _al_copy_bitmap_data(
+   const void *src, int src_pitch, void *dst, int dst_pitch,
+   int sx, int sy, int dx, int dy, int width, int height,
+   int format);
+
 /* Bitmap type conversion */ 
 void _al_init_convert_bitmap_list(void);
 void _al_register_convert_bitmap(ALLEGRO_BITMAP *bitmap);
@@ -146,6 +158,8 @@ void _al_put_pixel(ALLEGRO_BITMAP *bitmap, int x, int y, ALLEGRO_COLOR color);
 void _al_init_iio_table(void);
 
 
+int _al_get_bitmap_memory_format(ALLEGRO_BITMAP *bitmap);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/allegro5/internal/aintern_convert.h b/include/allegro5/internal/aintern_convert.h
index 51eb8a7..6ebdced 100644
--- a/include/allegro5/internal/aintern_convert.h
+++ b/include/allegro5/internal/aintern_convert.h
@@ -1561,11 +1561,11 @@
 #define ALLEGRO_CONVERT_RGBA_4444_TO_SINGLE_CHANNEL_8(x) \
    (_al_rgb_scale_4[(((x) >> 12) & 0xf)])
 #define ALLEGRO_CONVERT_SINGLE_CHANNEL_8_TO_ARGB_8888(x) \
-   (0xff000000 | \
+   (0xff000000L | \
    (((x) << 16) & 0xff0000))
 #define ALLEGRO_CONVERT_SINGLE_CHANNEL_8_TO_RGBA_8888(x) \
    (0xff | \
-   (((x) << 24) & 0xff000000))
+   (((x) << 24) & 0xff000000L))
 #define ALLEGRO_CONVERT_SINGLE_CHANNEL_8_TO_ARGB_4444(x) \
    (0xf000 | \
    (((x) << 4) & 0xf00))
@@ -1582,7 +1582,7 @@
    (0x8000 | \
    (((x) << 7) & 0x7c00))
 #define ALLEGRO_CONVERT_SINGLE_CHANNEL_8_TO_ABGR_8888(x) \
-   (0xff000000 | \
+   (0xff000000L | \
    ((x) & 0xff))
 #define ALLEGRO_CONVERT_SINGLE_CHANNEL_8_TO_XBGR_8888(x) \
    (((x) & 0xff))
@@ -1593,7 +1593,7 @@
 #define ALLEGRO_CONVERT_SINGLE_CHANNEL_8_TO_BGR_555(x) \
    ((((x) >> 3) & 0x1f))
 #define ALLEGRO_CONVERT_SINGLE_CHANNEL_8_TO_RGBX_8888(x) \
-   ((((x) << 24) & 0xff000000))
+   ((((x) << 24) & 0xff000000L))
 #define ALLEGRO_CONVERT_SINGLE_CHANNEL_8_TO_XRGB_8888(x) \
    ((((x) << 16) & 0xff0000))
 #define ALLEGRO_CONVERT_SINGLE_CHANNEL_8_TO_ABGR_F32(x) \
@@ -1601,10 +1601,10 @@
 #ifdef ALLEGRO_BIG_ENDIAN
 #define ALLEGRO_CONVERT_SINGLE_CHANNEL_8_TO_ABGR_8888_LE(x) \
    (0xff | \
-   (((x) << 24) & 0xff000000))
+   (((x) << 24) & 0xff000000L))
 #else
 #define ALLEGRO_CONVERT_SINGLE_CHANNEL_8_TO_ABGR_8888_LE(x) \
-   (0xff000000 | \
+   (0xff000000L | \
    ((x) & 0xff))
 #endif
 #define ALLEGRO_CONVERT_SINGLE_CHANNEL_8_TO_RGBA_4444(x) \
diff --git a/include/allegro5/internal/aintern_direct3d.h b/include/allegro5/internal/aintern_direct3d.h
index e766317..d69819c 100644
--- a/include/allegro5/internal/aintern_direct3d.h
+++ b/include/allegro5/internal/aintern_direct3d.h
@@ -18,6 +18,7 @@ typedef struct ALLEGRO_BITMAP_EXTRA_D3D
 
    LPDIRECT3DTEXTURE9 video_texture;
    LPDIRECT3DTEXTURE9 system_texture;
+   int system_format;
 
    bool initialized;
    bool is_backbuffer;
@@ -83,12 +84,25 @@ void _al_d3d_destroy_bitmap(ALLEGRO_BITMAP *bitmap);
 void _al_d3d_update_render_state(ALLEGRO_DISPLAY *display);
 
 #ifdef ALLEGRO_CFG_SHADER_HLSL
-   bool _al_load_d3dx9_module();
-   void _al_unload_d3dx9_module();
    bool _al_hlsl_set_projview_matrix(LPD3DXEFFECT effect,
       const ALLEGRO_TRANSFORM *t);
 #endif
 
+typedef HRESULT (WINAPI *_ALLEGRO_D3DXLSFLSPROC)(LPDIRECT3DSURFACE9, const PALETTEENTRY*,
+   const RECT*, LPDIRECT3DSURFACE9, const PALETTEENTRY*, const RECT*,
+   DWORD, D3DCOLOR);
+
+typedef HRESULT (WINAPI *_ALLEGRO_D3DXCREATEEFFECTPROC)(LPDIRECT3DDEVICE9, LPCVOID, UINT,
+   CONST D3DXMACRO*, LPD3DXINCLUDE, DWORD, LPD3DXEFFECTPOOL, LPD3DXEFFECT*,
+   LPD3DXBUFFER*);
+
+#ifdef ALLEGRO_CFG_D3DX9
+   bool _al_load_d3dx9_module();
+   void _al_unload_d3dx9_module();
+
+   extern _ALLEGRO_D3DXLSFLSPROC _al_imp_D3DXLoadSurfaceFromSurface;
+   extern _ALLEGRO_D3DXCREATEEFFECTPROC _al_imp_D3DXCreateEffect;
+#endif
 
 #ifdef __cplusplus
 }
diff --git a/include/allegro5/internal/aintern_opengl.h b/include/allegro5/internal/aintern_opengl.h
index 4766de0..bb17c2f 100644
--- a/include/allegro5/internal/aintern_opengl.h
+++ b/include/allegro5/internal/aintern_opengl.h
@@ -157,6 +157,8 @@ void _al_ogl_upload_bitmap_memory(ALLEGRO_BITMAP *bitmap, int format, void *ptr)
    void _al_ogl_unlock_region_gles(ALLEGRO_BITMAP *bitmap);
 #endif
 
+int _al_ogl_pixel_alignment(int pixel_size, bool compressed);
+
 /* framebuffer objects */
 GLint _al_ogl_bind_framebuffer(GLint fbo);
 void _al_ogl_reset_fbo_info(ALLEGRO_FBO_INFO *info);
diff --git a/include/allegro5/internal/aintern_pixels.h b/include/allegro5/internal/aintern_pixels.h
index 49ac749..4aba9b9 100644
--- a/include/allegro5/internal/aintern_pixels.h
+++ b/include/allegro5/internal/aintern_pixels.h
@@ -252,6 +252,13 @@
             abort();                                                          \
             break;                                                            \
                                                                               \
+         case ALLEGRO_PIXEL_FORMAT_RGBA_DXT1:                                 \
+         case ALLEGRO_PIXEL_FORMAT_RGBA_DXT3:                                 \
+         case ALLEGRO_PIXEL_FORMAT_RGBA_DXT5:                                 \
+            ALLEGRO_ERROR("INLINE_GET got compressed format: %d\n", format); \
+            abort();                                                          \
+            break;                                                            \
+                                                                              \
          case ALLEGRO_NUM_PIXEL_FORMATS:                                      \
          default:                                                             \
             ALLEGRO_ERROR("INLINE_GET got non pixel format: %d\n", format); \
@@ -460,6 +467,13 @@
             abort();                                                          \
             break;                                                            \
                                                                               \
+         case ALLEGRO_PIXEL_FORMAT_RGBA_DXT1:                                 \
+         case ALLEGRO_PIXEL_FORMAT_RGBA_DXT3:                                 \
+         case ALLEGRO_PIXEL_FORMAT_RGBA_DXT5:                                 \
+            ALLEGRO_ERROR("INLINE_PUT got compressed format: %d\n", format); \
+            abort();                                                          \
+            break;                                                            \
+                                                                              \
          case ALLEGRO_NUM_PIXEL_FORMATS:                                      \
             ALLEGRO_ERROR("INLINE_PUT got non _pp_pixel format: %d\n", format); \
             abort();                                                          \
@@ -476,6 +490,8 @@ AL_ARRAY(float, _al_u8_to_float);
 void _al_init_pixels(void);
 bool _al_pixel_format_has_alpha(int format);
 bool _al_pixel_format_is_real(int format);
+bool _al_pixel_format_is_video_only(int format);
+bool _al_pixel_format_is_compressed(int format);
 int _al_get_real_pixel_format(ALLEGRO_DISPLAY *display, int format);
 char const *_al_pixel_format_name(ALLEGRO_PIXEL_FORMAT format);
 
diff --git a/include/allegro5/platform/alplatf.h.cmake b/include/allegro5/platform/alplatf.h.cmake
index d48696f..bf5b9f5 100644
--- a/include/allegro5/platform/alplatf.h.cmake
+++ b/include/allegro5/platform/alplatf.h.cmake
@@ -14,6 +14,7 @@
 
 #cmakedefine ALLEGRO_CFG_D3D
 #cmakedefine ALLEGRO_CFG_D3D9EX
+#cmakedefine ALLEGRO_CFG_D3DX9
 #cmakedefine ALLEGRO_CFG_XINPUT
 #cmakedefine ALLEGRO_CFG_OPENGL
 #cmakedefine ALLEGRO_CFG_OPENGLES
diff --git a/misc/make_converters.py b/misc/make_converters.py
index 28c8183..da2165b 100755
--- a/misc/make_converters.py
+++ b/misc/make_converters.py
@@ -27,6 +27,7 @@ def parse_format(format):
     Parse the format name into an info structure.
     """
     if format.startswith("ANY"): return None
+    if "DXT" in format: return None
 
     separator = format.find("_")
     class Info: pass
diff --git a/src/allegro.c b/src/allegro.c
index 53754c1..92bbbc7 100644
--- a/src/allegro.c
+++ b/src/allegro.c
@@ -18,6 +18,7 @@
 
 #include "allegro5/allegro.h"
 #include "allegro5/platform/alplatf.h"
+#include "allegro5/internal/aintern.h"
 
 
 
@@ -41,5 +42,13 @@ int al_run_main(int argc, char **argv, int (*user_main)(int, char **))
 #endif
 }
 
+int _al_get_least_multiple(int val, int mul)
+{
+   int rem = val % mul;
+   if (rem == 0)
+      return val;
+   else
+      return val + mul - rem;
+}
 
 /* vim: set sts=3 sw=3 et: */
diff --git a/src/android/android_display.c b/src/android/android_display.c
index c9c73fd..b1b63ce 100644
--- a/src/android/android_display.c
+++ b/src/android/android_display.c
@@ -856,7 +856,8 @@ static void android_acknowledge_drawing_resume(ALLEGRO_DISPLAY *dpy)
          !(bitmap_flags & ALLEGRO_MEMORY_BITMAP) &&
          !(bitmap_flags & ALLEGRO_NO_PRESERVE_TEXTURE))
       {
-         _al_ogl_upload_bitmap_memory(bmp, al_get_bitmap_format(bmp), bmp->memory);
+         int format = _al_pixel_format_is_compressed(format) ? ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE : format;
+         _al_ogl_upload_bitmap_memory(bmp, bmp->memory_format, bmp->memory);
          bmp->dirty = false;
       }
    }
diff --git a/src/bitmap.c b/src/bitmap.c
index 44ccc9d..f1c95f3 100644
--- a/src/bitmap.c
+++ b/src/bitmap.c
@@ -39,6 +39,11 @@ static ALLEGRO_BITMAP *create_memory_bitmap(ALLEGRO_DISPLAY *current_display,
    ALLEGRO_BITMAP *bitmap;
    int pitch;
 
+   if (_al_pixel_format_is_video_only(format)) {
+      /* Can't have a video-only memory bitmap... */
+      return NULL;
+   }
+
    format = _al_get_real_pixel_format(current_display, format);
 
    bitmap = al_calloc(1, sizeof *bitmap);
@@ -298,6 +303,15 @@ int al_get_bitmap_format(ALLEGRO_BITMAP *bitmap)
 }
 
 
+int _al_get_bitmap_memory_format(ALLEGRO_BITMAP *bitmap)
+{
+   if (bitmap->parent)
+      return bitmap->parent->_memory_format;
+   else
+      return bitmap->_memory_format;
+}
+
+
 
 /* Function: al_get_bitmap_flags
  */
@@ -446,26 +460,97 @@ ALLEGRO_BITMAP *al_get_parent_bitmap(ALLEGRO_BITMAP *bitmap)
 }
 
 
-static void transfer_bitmap_data(ALLEGRO_BITMAP *src, ALLEGRO_BITMAP *dst)
+static bool transfer_bitmap_data(ALLEGRO_BITMAP *src, ALLEGRO_BITMAP *dst)
 {
    ALLEGRO_LOCKED_REGION *dst_region;
    ALLEGRO_LOCKED_REGION *src_region;
+   int src_format = al_get_bitmap_format(src);
+   int dst_format = al_get_bitmap_format(dst);
+   bool src_compressed = _al_pixel_format_is_compressed(src_format);
+   bool dst_compressed = _al_pixel_format_is_compressed(dst_format);
+   int copy_w = src->w;
+   int copy_h = src->h;
+   
+   if (src_compressed && dst_compressed && src_format == dst_format) {
+      int block_width = al_get_pixel_block_width(src_format);
+      if (!(src_region = al_lock_bitmap_blocked(src, ALLEGRO_LOCK_READONLY)))
+         return false;
+
+      if (!(dst_region = al_lock_bitmap_blocked(dst, ALLEGRO_LOCK_WRITEONLY))) {
+         al_unlock_bitmap(src);
+         return false;
+      }
+      copy_w = _al_get_least_multiple(copy_w, block_width);
+      copy_h = _al_get_least_multiple(copy_h, block_width);
+      ALLEGRO_DEBUG("Taking fast clone path");
+   }
+   else {
+      int lock_format = ALLEGRO_PIXEL_FORMAT_ANY;
+      /* Go through a non-compressed intermediate */
+      if (src_compressed && !dst_compressed) {
+         lock_format = dst_format;
+      }
+      else if (!src_compressed && dst_compressed) {
+         lock_format = src_format;
+      }
+      
+      if (!(src_region = al_lock_bitmap(src, lock_format, ALLEGRO_LOCK_READONLY)))
+         return false;
 
-   if (!(src_region = al_lock_bitmap(src, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_READONLY)))
-      return;
-
-   if (!(dst_region = al_lock_bitmap(dst, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_WRITEONLY))) {
-      al_unlock_bitmap(src);
-      return;
+      if (!(dst_region = al_lock_bitmap(dst, lock_format, ALLEGRO_LOCK_WRITEONLY))) {
+         al_unlock_bitmap(src);
+         return false;
+      }
    }
 
    _al_convert_bitmap_data(
       src_region->data, src_region->format, src_region->pitch,
       dst_region->data, dst_region->format, dst_region->pitch,
-      0, 0, 0, 0, src->w, src->h);
+      0, 0, 0, 0, copy_w, copy_h);
 
    al_unlock_bitmap(src);
    al_unlock_bitmap(dst);
+
+   return true;
+}
+
+
+void _al_copy_bitmap_data(
+   const void *src, int src_pitch, void *dst, int dst_pitch,
+   int sx, int sy, int dx, int dy, int width, int height,
+   int format)
+{
+   int block_width = al_get_pixel_block_width(format);
+   int block_size = al_get_pixel_block_size(format);
+   const char *src_ptr = src;
+   char *dst_ptr = dst;
+   int y;
+
+   ASSERT(src);
+   ASSERT(dst);
+   ASSERT(_al_pixel_format_is_real(format));
+   ASSERT(height % block_width == 0);
+   ASSERT(width % block_width == 0);
+   ASSERT(sx % block_width == 0);
+   ASSERT(sy % block_width == 0);
+   ASSERT(dy % block_width == 0);
+   ASSERT(dx % block_width == 0);
+
+   sx /= block_width;
+   sy /= block_width;
+   dx /= block_width;
+   dy /= block_width;
+   width /= block_width;
+   height /= block_width;
+
+   src_ptr += sy * src_pitch + sx * block_size;
+   dst_ptr += dy * dst_pitch + dx * block_size;
+
+   for (y = 0; y < height; y++) {
+      memcpy(dst_ptr, src_ptr, width * block_size);
+      src_ptr += src_pitch;
+      dst_ptr += dst_pitch;
+   }
 }
 
 
@@ -480,19 +565,16 @@ void _al_convert_bitmap_data(
 
    /* Use memcpy if no conversion is needed. */
    if (src_format == dst_format) {
-      int y;
-      int size = al_get_pixel_size(src_format);
-      const char *src_ptr = ((const char *)src) + sy * src_pitch + sx * size;
-      char *dst_ptr = ((char *)dst) + dy * dst_pitch + dx * size;
-      width *= size;
-      for (y = 0; y < height; y++) {
-         memcpy(dst_ptr, src_ptr, width);
-         src_ptr += src_pitch;
-         dst_ptr += dst_pitch;
-      }
+      _al_copy_bitmap_data(src, src_pitch, dst, dst_pitch, sx, sy,
+         dx, dy, width, height, src_format);
       return;
    }
 
+   /* Video-only formats don't have conversion functions, so they should have
+    * been taken care of before reaching this location. */
+   ASSERT(!_al_pixel_format_is_video_only(src_format));
+   ASSERT(!_al_pixel_format_is_video_only(dst_format));
+
    (_al_convert_funcs[src_format][dst_format])(src, src_pitch,
       dst, dst_pitch, sx, sy, dx, dy, width, height);
 }
@@ -508,7 +590,10 @@ ALLEGRO_BITMAP *al_clone_bitmap(ALLEGRO_BITMAP *bitmap)
    clone = al_create_bitmap(bitmap->w, bitmap->h);
    if (!clone)
       return NULL;
-   transfer_bitmap_data(bitmap, clone);
+   if (!transfer_bitmap_data(bitmap, clone)) {
+      al_destroy_bitmap(clone);
+      return NULL;
+   }
    return clone;
 }
 
diff --git a/src/bitmap_draw.c b/src/bitmap_draw.c
index 07251b3..bafee87 100644
--- a/src/bitmap_draw.c
+++ b/src/bitmap_draw.c
@@ -18,6 +18,7 @@
 #include "allegro5/internal/aintern_bitmap.h"
 #include "allegro5/internal/aintern_display.h"
 #include "allegro5/internal/aintern_memblit.h"
+#include "allegro5/internal/aintern_pixels.h"
 
 
 static ALLEGRO_COLOR solid_white = {1, 1, 1, 1};
@@ -33,7 +34,8 @@ static void _bitmap_drawer(ALLEGRO_BITMAP *bitmap, ALLEGRO_COLOR tint,
    ASSERT(bitmap != dest && bitmap != dest->parent);
 
    /* If destination is memory, do a memory blit */
-   if (al_get_bitmap_flags(dest) & ALLEGRO_MEMORY_BITMAP) {
+   if (al_get_bitmap_flags(dest) & ALLEGRO_MEMORY_BITMAP
+         || _al_pixel_format_is_compressed(al_get_bitmap_format(dest))) {
       _al_draw_bitmap_region_memory(bitmap, tint, sx, sy, sw, sh, 0, 0, flags);
    }
    else {
diff --git a/src/bitmap_lock.c b/src/bitmap_lock.c
index f6868cb..6e3fada 100644
--- a/src/bitmap_lock.c
+++ b/src/bitmap_lock.c
@@ -28,10 +28,13 @@ ALLEGRO_LOCKED_REGION *al_lock_bitmap_region(ALLEGRO_BITMAP *bitmap,
    ALLEGRO_LOCKED_REGION *lr;
    int bitmap_format = al_get_bitmap_format(bitmap);
    int bitmap_flags = al_get_bitmap_flags(bitmap);
+   int block_width = al_get_pixel_block_width(bitmap_format);
+   int xc, yc, wc, hc;
    ASSERT(x >= 0);
    ASSERT(y >= 0);
    ASSERT(width >= 0);
    ASSERT(height >= 0);
+   ASSERT(!_al_pixel_format_is_video_only(format));
 
    /* For sub-bitmaps */
    if (bitmap->parent) {
@@ -50,12 +53,25 @@ ALLEGRO_LOCKED_REGION *al_lock_bitmap_region(ALLEGRO_BITMAP *bitmap,
    ASSERT(x+width <= bitmap->w);
    ASSERT(y+height <= bitmap->h);
 
-   bitmap->lock_x = x;
-   bitmap->lock_y = y;
-   bitmap->lock_w = width;
-   bitmap->lock_h = height;
+   xc = (x / block_width) * block_width;
+   yc = (y / block_width) * block_width;
+   wc = _al_get_least_multiple(x + width, block_width) - xc;
+   hc = _al_get_least_multiple(y + height, block_width) - yc;
+
+   bitmap->lock_x = xc;
+   bitmap->lock_y = yc;
+   bitmap->lock_w = wc;
+   bitmap->lock_h = hc;
    bitmap->lock_flags = flags;
 
+   if (flags == ALLEGRO_LOCK_WRITEONLY
+         && (xc != x || yc != y || wc != width || hc != height)) {
+      /* Unaligned write-only access requires that we fill in the padding
+       * from the texture.
+       * XXX: In principle, this could be done more efficiently. */
+      flags = ALLEGRO_LOCK_READWRITE;
+   }
+
    if (bitmap_flags & ALLEGRO_MEMORY_BITMAP) {
       int f = _al_get_real_pixel_format(al_get_current_display(), format);
       if (f < 0) {
@@ -64,32 +80,35 @@ ALLEGRO_LOCKED_REGION *al_lock_bitmap_region(ALLEGRO_BITMAP *bitmap,
       ASSERT(bitmap->memory);
       if (format == ALLEGRO_PIXEL_FORMAT_ANY || bitmap_format == format || bitmap_format == f) {
          bitmap->locked_region.data = bitmap->memory
-            + bitmap->pitch * y + x * al_get_pixel_size(bitmap_format);
+            + bitmap->pitch * yc + xc * al_get_pixel_size(bitmap_format);
          bitmap->locked_region.format = bitmap_format;
          bitmap->locked_region.pitch = bitmap->pitch;
          bitmap->locked_region.pixel_size = al_get_pixel_size(bitmap_format);
       }
       else {
-         bitmap->locked_region.pitch = al_get_pixel_size(f) * width;
-         bitmap->locked_region.data = al_malloc(bitmap->locked_region.pitch*height);
+         bitmap->locked_region.pitch = al_get_pixel_size(f) * wc;
+         bitmap->locked_region.data = al_malloc(bitmap->locked_region.pitch*hc);
          bitmap->locked_region.format = f;
          bitmap->locked_region.pixel_size = al_get_pixel_size(f);
          if (!(bitmap->lock_flags & ALLEGRO_LOCK_WRITEONLY)) {
             _al_convert_bitmap_data(
                bitmap->memory, bitmap_format, bitmap->pitch,
                bitmap->locked_region.data, f, bitmap->locked_region.pitch,
-               x, y, 0, 0, width, height);
+               xc, yc, 0, 0, wc, hc);
          }
       }
       lr = &bitmap->locked_region;
    }
    else {
-      lr = bitmap->vt->lock_region(bitmap, x, y, width, height, format, flags);
+      lr = bitmap->vt->lock_region(bitmap, xc, yc, wc, hc, format, flags);
       if (!lr) {
          return NULL;
       }
    }
 
+   /* Fixup the data pointer for unaligned access */
+   lr->data = (char*)lr->data + (xc - x) * lr->pixel_size + (yc - y) * lr->pitch;
+
    bitmap->locked = true;
 
    return lr;
@@ -116,7 +135,10 @@ void al_unlock_bitmap(ALLEGRO_BITMAP *bitmap)
    }
 
    if (!(al_get_bitmap_flags(bitmap) & ALLEGRO_MEMORY_BITMAP)) {
-      bitmap->vt->unlock_region(bitmap);
+      if (_al_pixel_format_is_compressed(bitmap->locked_region.format))
+         bitmap->vt->unlock_compressed_region(bitmap);
+      else
+         bitmap->vt->unlock_region(bitmap);
    }
    else {
       if (bitmap->locked_region.format != 0 && bitmap->locked_region.format != bitmap_format) {
@@ -141,5 +163,80 @@ bool al_is_bitmap_locked(ALLEGRO_BITMAP *bitmap)
    return bitmap->locked;
 }
 
+/* Function: al_lock_bitmap_region_blocked
+ */
+ALLEGRO_LOCKED_REGION *al_lock_bitmap_blocked(ALLEGRO_BITMAP *bitmap,
+   int flags)
+{
+   int bitmap_format = al_get_bitmap_format(bitmap);
+   int block_width = al_get_pixel_block_width(bitmap_format);
+   
+   return al_lock_bitmap_region_blocked(bitmap, 0, 0, 
+      _al_get_least_multiple(bitmap->w, block_width) / block_width,
+      _al_get_least_multiple(bitmap->h, block_width) / block_width,
+      flags);
+}
+
+/* Function: al_lock_bitmap_region_blocked
+ */
+ALLEGRO_LOCKED_REGION *al_lock_bitmap_region_blocked(ALLEGRO_BITMAP *bitmap,
+   int x_block, int y_block, int width_block, int height_block, int flags)
+{
+   ALLEGRO_LOCKED_REGION *lr;
+   int bitmap_format = al_get_bitmap_format(bitmap);
+   int bitmap_flags = al_get_bitmap_flags(bitmap);
+   int block_width = al_get_pixel_block_width(bitmap_format);
+   ASSERT(x_block >= 0);
+   ASSERT(y_block >= 0);
+   ASSERT(width_block >= 0);
+   ASSERT(height_block >= 0);
+   
+   if (block_width == 1 && !_al_pixel_format_is_video_only(bitmap_format)) {
+      return al_lock_bitmap_region(bitmap, x_block, y_block, width_block,
+         height_block, bitmap_format, flags);
+   }
+   
+   /* Currently, this is the only format that gets to this point */
+   ASSERT(_al_pixel_format_is_compressed(bitmap_format));
+   ASSERT(!(bitmap_flags & ALLEGRO_MEMORY_BITMAP));
+   
+   /* For sub-bitmaps */
+   if (bitmap->parent) {
+      if (bitmap->xofs % block_width != 0
+            || bitmap->yofs % block_width != 0) {
+         return NULL;
+      }
+      x_block += bitmap->xofs / block_width;
+      y_block += bitmap->yofs / block_width;
+      bitmap = bitmap->parent;
+   }
+
+   if (bitmap->locked)
+      return NULL;
+
+   if (!(flags & ALLEGRO_LOCK_READONLY))
+      bitmap->dirty = true;
+
+   ASSERT(x_block + width_block
+      <= _al_get_least_multiple(bitmap->w, block_width) / block_width);
+   ASSERT(y_block + height_block
+      <= _al_get_least_multiple(bitmap->h, block_width) / block_width);
+
+   bitmap->lock_x = x_block * block_width;
+   bitmap->lock_y = y_block * block_width;
+   bitmap->lock_w = width_block * block_width;
+   bitmap->lock_h = height_block * block_width;
+   bitmap->lock_flags = flags;
+
+   lr = bitmap->vt->lock_compressed_region(bitmap, bitmap->lock_x, 
+      bitmap->lock_y, bitmap->lock_w, bitmap->lock_h, flags);
+   if (!lr) {
+      return NULL;
+   }
+
+   bitmap->locked = true;
+
+   return lr;
+}
 
 /* vim: set ts=8 sts=3 sw=3 et: */
diff --git a/src/bitmap_pixel.c b/src/bitmap_pixel.c
index 8ef5537..052214f 100644
--- a/src/bitmap_pixel.c
+++ b/src/bitmap_pixel.c
@@ -28,8 +28,7 @@ ALLEGRO_COLOR al_get_pixel(ALLEGRO_BITMAP *bitmap, int x, int y)
 {
    ALLEGRO_LOCKED_REGION *lr;
    char *data;
-   ALLEGRO_COLOR color;
-   int bitmap_format = al_get_bitmap_format(bitmap);
+   ALLEGRO_COLOR color = al_map_rgba_f(0, 0, 0, 0);
 
    if (bitmap->parent) {
       x += bitmap->xofs;
@@ -38,11 +37,14 @@ ALLEGRO_COLOR al_get_pixel(ALLEGRO_BITMAP *bitmap, int x, int y)
    }
 
    if (bitmap->locked) {
+      if (_al_pixel_format_is_video_only(bitmap->locked_region.format)) {
+         ALLEGRO_ERROR("Invalid lock format.");
+         return color;
+      }
       x -= bitmap->lock_x;
       y -= bitmap->lock_y;
       if (x < 0 || y < 0 || x >= bitmap->lock_w || y >= bitmap->lock_h) {
          ALLEGRO_ERROR("Out of bounds.");
-         memset(&color, 0, sizeof(ALLEGRO_COLOR));
          return color;
       }
 
@@ -55,21 +57,18 @@ ALLEGRO_COLOR al_get_pixel(ALLEGRO_BITMAP *bitmap, int x, int y)
    else {
       /* FIXME: must use clip not full bitmap */
       if (x < 0 || y < 0 || x >= bitmap->w || y >= bitmap->h) {
-         memset(&color, 0, sizeof(ALLEGRO_COLOR));
          return color;
       }
 
-      if (!(lr = al_lock_bitmap_region(bitmap, x, y, 1, 1, bitmap_format,
-            ALLEGRO_LOCK_READONLY)))
-      {
-         memset(&color, 0, sizeof(ALLEGRO_COLOR));
+      if (!(lr = al_lock_bitmap_region(bitmap, x, y, 1, 1, 
+            ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_READONLY))) {
          return color;
       }
 
       /* FIXME: check for valid pixel format */
 
       data = lr->data;
-      _AL_INLINE_GET_PIXEL(bitmap_format, data, color, false);
+      _AL_INLINE_GET_PIXEL(lr->format, data, color, false);
 
       al_unlock_bitmap(bitmap);
    }
@@ -82,7 +81,6 @@ void _al_put_pixel(ALLEGRO_BITMAP *bitmap, int x, int y, ALLEGRO_COLOR color)
 {
    ALLEGRO_LOCKED_REGION *lr;
    char *data;
-   int bitmap_format = al_get_bitmap_format(bitmap);
 
    if (bitmap->parent) {
        x += bitmap->xofs;
@@ -91,12 +89,15 @@ void _al_put_pixel(ALLEGRO_BITMAP *bitmap, int x, int y, ALLEGRO_COLOR color)
    }
 
    if (x < bitmap->cl || y < bitmap->ct ||
-       x >= bitmap->cr_excl || y >= bitmap->cb_excl)
-   {
+       x >= bitmap->cr_excl || y >= bitmap->cb_excl) {
       return;
    }
 
    if (bitmap->locked) {
+      if (_al_pixel_format_is_video_only(bitmap->locked_region.format)) {
+         ALLEGRO_ERROR("Invalid lock format.");
+         return;
+      }
       x -= bitmap->lock_x;
       y -= bitmap->lock_y;
       if (x < 0 || y < 0 || x >= bitmap->lock_w || y >= bitmap->lock_h) {
@@ -110,15 +111,15 @@ void _al_put_pixel(ALLEGRO_BITMAP *bitmap, int x, int y, ALLEGRO_COLOR color)
       _AL_INLINE_PUT_PIXEL(bitmap->locked_region.format, data, color, false);
    }
    else {
-      lr = al_lock_bitmap_region(bitmap, x, y, 1, 1, bitmap_format,
-         ALLEGRO_LOCK_WRITEONLY);
+      lr = al_lock_bitmap_region(bitmap, x, y, 1, 1,
+         ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_WRITEONLY);
       if (!lr)
          return;
 
       /* FIXME: check for valid pixel format */
 
       data = lr->data;
-      _AL_INLINE_PUT_PIXEL(bitmap_format, data, color, false);
+      _AL_INLINE_PUT_PIXEL(lr->format, data, color, false);
 
       al_unlock_bitmap(bitmap);
    }
diff --git a/src/convert.c b/src/convert.c
index 8995496..73eda47 100644
--- a/src/convert.c
+++ b/src/convert.c
@@ -8062,6 +8062,7 @@ void (*_al_convert_funcs[ALLEGRO_NUM_PIXEL_FORMATS]
       argb_8888_to_abgr_8888_le,
       argb_8888_to_rgba_4444,
       argb_8888_to_single_channel_8,
+      NULL, NULL, NULL,
    },
    {
       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
@@ -8084,6 +8085,7 @@ void (*_al_convert_funcs[ALLEGRO_NUM_PIXEL_FORMATS]
       rgba_8888_to_abgr_8888_le,
       rgba_8888_to_rgba_4444,
       rgba_8888_to_single_channel_8,
+      NULL, NULL, NULL,
    },
    {
       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
@@ -8106,6 +8108,7 @@ void (*_al_convert_funcs[ALLEGRO_NUM_PIXEL_FORMATS]
       argb_4444_to_abgr_8888_le,
       argb_4444_to_rgba_4444,
       argb_4444_to_single_channel_8,
+      NULL, NULL, NULL,
    },
    {
       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
@@ -8128,6 +8131,7 @@ void (*_al_convert_funcs[ALLEGRO_NUM_PIXEL_FORMATS]
       rgb_888_to_abgr_8888_le,
       rgb_888_to_rgba_4444,
       rgb_888_to_single_channel_8,
+      NULL, NULL, NULL,
    },
    {
       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
@@ -8150,6 +8154,7 @@ void (*_al_convert_funcs[ALLEGRO_NUM_PIXEL_FORMATS]
       rgb_565_to_abgr_8888_le,
       rgb_565_to_rgba_4444,
       rgb_565_to_single_channel_8,
+      NULL, NULL, NULL,
    },
    {
       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
@@ -8172,6 +8177,7 @@ void (*_al_convert_funcs[ALLEGRO_NUM_PIXEL_FORMATS]
       rgb_555_to_abgr_8888_le,
       rgb_555_to_rgba_4444,
       rgb_555_to_single_channel_8,
+      NULL, NULL, NULL,
    },
    {
       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
@@ -8194,6 +8200,7 @@ void (*_al_convert_funcs[ALLEGRO_NUM_PIXEL_FORMATS]
       rgba_5551_to_abgr_8888_le,
       rgba_5551_to_rgba_4444,
       rgba_5551_to_single_channel_8,
+      NULL, NULL, NULL,
    },
    {
       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
@@ -8216,6 +8223,7 @@ void (*_al_convert_funcs[ALLEGRO_NUM_PIXEL_FORMATS]
       argb_1555_to_abgr_8888_le,
       argb_1555_to_rgba_4444,
       argb_1555_to_single_channel_8,
+      NULL, NULL, NULL,
    },
    {
       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
@@ -8238,6 +8246,7 @@ void (*_al_convert_funcs[ALLEGRO_NUM_PIXEL_FORMATS]
       abgr_8888_to_abgr_8888_le,
       abgr_8888_to_rgba_4444,
       abgr_8888_to_single_channel_8,
+      NULL, NULL, NULL,
    },
    {
       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
@@ -8260,6 +8269,7 @@ void (*_al_convert_funcs[ALLEGRO_NUM_PIXEL_FORMATS]
       xbgr_8888_to_abgr_8888_le,
       xbgr_8888_to_rgba_4444,
       xbgr_8888_to_single_channel_8,
+      NULL, NULL, NULL,
    },
    {
       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
@@ -8282,6 +8292,7 @@ void (*_al_convert_funcs[ALLEGRO_NUM_PIXEL_FORMATS]
       bgr_888_to_abgr_8888_le,
       bgr_888_to_rgba_4444,
       bgr_888_to_single_channel_8,
+      NULL, NULL, NULL,
    },
    {
       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
@@ -8304,6 +8315,7 @@ void (*_al_convert_funcs[ALLEGRO_NUM_PIXEL_FORMATS]
       bgr_565_to_abgr_8888_le,
       bgr_565_to_rgba_4444,
       bgr_565_to_single_channel_8,
+      NULL, NULL, NULL,
    },
    {
       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
@@ -8326,6 +8338,7 @@ void (*_al_convert_funcs[ALLEGRO_NUM_PIXEL_FORMATS]
       bgr_555_to_abgr_8888_le,
       bgr_555_to_rgba_4444,
       bgr_555_to_single_channel_8,
+      NULL, NULL, NULL,
    },
    {
       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
@@ -8348,6 +8361,7 @@ void (*_al_convert_funcs[ALLEGRO_NUM_PIXEL_FORMATS]
       rgbx_8888_to_abgr_8888_le,
       rgbx_8888_to_rgba_4444,
       rgbx_8888_to_single_channel_8,
+      NULL, NULL, NULL,
    },
    {
       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
@@ -8370,6 +8384,7 @@ void (*_al_convert_funcs[ALLEGRO_NUM_PIXEL_FORMATS]
       xrgb_8888_to_abgr_8888_le,
       xrgb_8888_to_rgba_4444,
       xrgb_8888_to_single_channel_8,
+      NULL, NULL, NULL,
    },
    {
       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
@@ -8392,6 +8407,7 @@ void (*_al_convert_funcs[ALLEGRO_NUM_PIXEL_FORMATS]
       abgr_f32_to_abgr_8888_le,
       abgr_f32_to_rgba_4444,
       abgr_f32_to_single_channel_8,
+      NULL, NULL, NULL,
    },
    {
       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
@@ -8414,6 +8430,7 @@ void (*_al_convert_funcs[ALLEGRO_NUM_PIXEL_FORMATS]
       NULL,
       abgr_8888_le_to_rgba_4444,
       abgr_8888_le_to_single_channel_8,
+      NULL, NULL, NULL,
    },
    {
       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
@@ -8436,6 +8453,7 @@ void (*_al_convert_funcs[ALLEGRO_NUM_PIXEL_FORMATS]
       rgba_4444_to_abgr_8888_le,
       NULL,
       rgba_4444_to_single_channel_8,
+      NULL, NULL, NULL,
    },
    {
       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
@@ -8457,8 +8475,11 @@ void (*_al_convert_funcs[ALLEGRO_NUM_PIXEL_FORMATS]
       single_channel_8_to_abgr_f32,
       single_channel_8_to_abgr_8888_le,
       single_channel_8_to_rgba_4444,
-      NULL,
+      NULL, NULL, NULL, NULL,
    },
+   {NULL},
+   {NULL},
+   {NULL},
 };
 
 // Warning: This file was created by make_converters.py - do not edit.
diff --git a/src/drawing.c b/src/drawing.c
index 1a8d590..93b85cc 100644
--- a/src/drawing.c
+++ b/src/drawing.c
@@ -65,7 +65,8 @@ void al_draw_pixel(float x, float y, ALLEGRO_COLOR color)
 
    ASSERT(target);
 
-   if (al_get_bitmap_flags(target) & ALLEGRO_MEMORY_BITMAP) {
+   if (al_get_bitmap_flags(target) & ALLEGRO_MEMORY_BITMAP
+         || _al_pixel_format_is_compressed(al_get_bitmap_format(target))) {
       _al_draw_pixel_memory(target, x, y, &color);
    }
    else {
diff --git a/src/memblit.c b/src/memblit.c
index 0bd6a0a..7f823ce 100644
--- a/src/memblit.c
+++ b/src/memblit.c
@@ -281,20 +281,20 @@ static void _al_draw_bitmap_region_memory_fast(ALLEGRO_BITMAP *bitmap,
    CLIPPER(bitmap, sx, sy, sw, sh, dest, dx, dy, dw, dh, 1, 1, flags)
 
    if (!(src_region = al_lock_bitmap_region(bitmap, sx, sy, sw, sh,
-         al_get_bitmap_format(bitmap), ALLEGRO_LOCK_READONLY))) {
+         ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_READONLY))) {
       return;
    }
 
    if (!(dst_region = al_lock_bitmap_region(dest, dx, dy, sw, sh,
-         al_get_bitmap_format(dest), ALLEGRO_LOCK_WRITEONLY))) {
+         ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_WRITEONLY))) {
       al_unlock_bitmap(bitmap);
       return;
    }
 
    /* will detect if no conversion is needed */
    _al_convert_bitmap_data(
-      src_region->data, al_get_bitmap_format(bitmap), src_region->pitch,
-      dst_region->data, al_get_bitmap_format(dest), dst_region->pitch,
+      src_region->data, src_region->format, src_region->pitch,
+      dst_region->data, dst_region->format, dst_region->pitch,
       0, 0, 0, 0, sw, sh);
 
    al_unlock_bitmap(bitmap);
diff --git a/src/opengl/ogl_bitmap.c b/src/opengl/ogl_bitmap.c
index 645e54e..b116d48 100644
--- a/src/opengl/ogl_bitmap.c
+++ b/src/opengl/ogl_bitmap.c
@@ -119,6 +119,9 @@ int _al_ogl_get_glformat(int format, int component)
       {GL_RGBA, GL_UNSIGNED_BYTE, GL_RGBA}, /* ABGR_8888_LE */
       {GL_RGBA4, GL_UNSIGNED_SHORT_4_4_4_4, GL_RGBA}, /* RGBA_4444 */
       {GL_LUMINANCE, GL_UNSIGNED_BYTE, GL_LUMINANCE}, /* SINGLE_CHANNEL_8 */
+      {GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_UNSIGNED_INT_8_8_8_8, GL_RGBA}, /* RGBA_DXT1 */
+      {GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_UNSIGNED_INT_8_8_8_8, GL_RGBA}, /* RGBA_DXT3 */
+      {GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_UNSIGNED_INT_8_8_8_8, GL_RGBA}, /* RGBA_DXT5 */
    };
   
    if (al_get_opengl_version() >= _ALLEGRO_OPENGL_VERSION_3_0) {
@@ -157,6 +160,9 @@ int _al_ogl_get_glformat(int format, int component)
       {GL_RGBA, GL_UNSIGNED_BYTE, GL_RGBA}, /* ABGR_8888_LE */
       {GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, GL_RGBA}, /* RGBA_4444 */
       {GL_LUMINANCE, GL_UNSIGNED_BYTE, GL_LUMINANCE}, /* SINGLE_CHANNEL_8 */
+      {0, 0, 0},
+      {0, 0, 0},
+      {0, 0, 0},
    };
    #endif
    
@@ -378,6 +384,7 @@ static int pot(int x)
 }
 
 
+
 // FIXME: need to do all the logic AllegroGL does, checking extensions,
 // proxy textures, formats, limits ...
 static bool ogl_upload_bitmap(ALLEGRO_BITMAP *bitmap)
@@ -582,6 +589,292 @@ static void ogl_bitmap_pointer_changed(ALLEGRO_BITMAP *bitmap,
    }
 }
 
+static void ogl_flip_blocks(ALLEGRO_LOCKED_REGION *lr, int wc, int hc)
+{
+#define SWAP(x, y) do { unsigned char t = x; x = y; y = t; } while (0)
+   int x, y;
+   unsigned char* data = lr->data;
+   switch (lr->format) {
+      case ALLEGRO_PIXEL_FORMAT_RGBA_DXT1: {
+         for (y = 0; y < hc; y++) {
+            unsigned char* row = data;
+            for (x = 0; x < wc; x++) {
+               /* Skip color table */
+               row += 4;
+
+               /* Swap colors */
+               SWAP(row[0], row[3]);
+               SWAP(row[2], row[1]);
+
+               /* Skip bit-map */
+               row += 4;
+            }
+            data += lr->pitch;
+         }
+         break;
+      }
+      case ALLEGRO_PIXEL_FORMAT_RGBA_DXT3: {
+         for (y = 0; y < hc; y++) {
+            unsigned char* row = data;
+            for (x = 0; x < wc; x++) {
+               /* Swap alpha */
+               SWAP(row[0], row[6]);
+               SWAP(row[1], row[7]);
+               SWAP(row[2], row[4]);
+               SWAP(row[3], row[5]);
+
+               /* Skip alpha bit-map */
+               row += 8;
+
+               /* Skip color table */
+               row += 4;
+
+               /* Swap colors */
+               SWAP(row[0], row[3]);
+               SWAP(row[2], row[1]);
+
+               /* Skip bit-map */
+               row += 4;
+            }
+            data += lr->pitch;
+         }
+         break;
+      }
+      case ALLEGRO_PIXEL_FORMAT_RGBA_DXT5: {
+         for (y = 0; y < hc; y++) {
+            unsigned char* row = data;
+            for (x = 0; x < wc; x++) {
+               uint16_t bit_row0, bit_row1, bit_row2, bit_row3;
+
+               /* Skip the alpha table */
+               row += 2;
+
+               bit_row0 = (((uint16_t)row[0]) | (uint16_t)row[1] << 8) << 4;
+               bit_row1 = (((uint16_t)row[1]) | (uint16_t)row[2] << 8) >> 4;
+               bit_row2 = (((uint16_t)row[3]) | (uint16_t)row[4] << 8) << 4;
+               bit_row3 = (((uint16_t)row[4]) | (uint16_t)row[5] << 8) >> 4;
+
+               row[0] = (unsigned char)(bit_row3 & 0x00ff);
+               row[1] = (unsigned char)((bit_row2 & 0x00ff) | ((bit_row3 & 0xff00) >> 8));
+               row[2] = (unsigned char)((bit_row2 & 0xff00) >> 8);
+
+               row[3] = (unsigned char)(bit_row1 & 0x00ff);
+               row[4] = (unsigned char)((bit_row0 & 0x00ff) | ((bit_row1 & 0xff00) >> 8));
+               row[5] = (unsigned char)((bit_row0 & 0xff00) >> 8);
+
+               /* Skip the alpha bit-map */
+               row += 6;
+
+               /* Skip color table */
+               row += 4;
+
+               /* Swap colors */
+               SWAP(row[0], row[3]);
+               SWAP(row[2], row[1]);
+
+               /* Skip bit-map */
+               row += 4;
+            }
+            data += lr->pitch;
+         }
+         break;
+      }
+   }
+#undef SWAP
+}
+
+static ALLEGRO_LOCKED_REGION *ogl_lock_compressed_region(ALLEGRO_BITMAP *bitmap,
+   int x, int y, int w, int h, int flags)
+{
+   ALLEGRO_BITMAP_EXTRA_OPENGL *const ogl_bitmap = bitmap->extra;
+   ALLEGRO_DISPLAY *disp;
+   ALLEGRO_DISPLAY *old_disp = NULL;
+   GLenum e;
+   bool ok = true;
+   int bitmap_format = al_get_bitmap_format(bitmap);
+   int block_width = al_get_pixel_block_width(bitmap_format);
+   int block_size = al_get_pixel_block_size(bitmap_format);
+   int xc = x / block_width;
+   int yc = y / block_width;
+   int wc = w / block_width;
+   int hc = h / block_width;
+   int true_wc = ogl_bitmap->true_w / block_width;
+   int true_hc = ogl_bitmap->true_h / block_width;
+   int gl_yc = _al_get_least_multiple(bitmap->h, block_width) / block_width - yc - hc;
+   
+   if (flags & ALLEGRO_LOCK_WRITEONLY) {
+      int pitch = wc * block_size;
+      ogl_bitmap->lock_buffer = al_malloc(pitch * hc);
+      if (ogl_bitmap->lock_buffer == NULL) {
+         return NULL;
+      }
+
+      bitmap->locked_region.data = ogl_bitmap->lock_buffer + pitch * (hc - 1);
+      bitmap->locked_region.format = bitmap_format;
+      bitmap->locked_region.pitch = -pitch;
+      bitmap->locked_region.pixel_size = block_size;
+      return &bitmap->locked_region;
+   }
+
+   disp = al_get_current_display();
+
+   /* Change OpenGL context if necessary. */
+   if (!disp ||
+      (_al_get_bitmap_display(bitmap)->ogl_extras->is_shared == false &&
+       _al_get_bitmap_display(bitmap) != disp))
+   {
+      old_disp = disp;
+      _al_set_current_display_only(_al_get_bitmap_display(bitmap));
+   }
+
+   /* Set up the pixel store state.  We will need to match it when unlocking.
+    * There may be other pixel store state we should be setting.
+    * See also pitfalls 7 & 8 from:
+    * http://www.opengl.org/resources/features/KilgardTechniques/oglpitfall/
+    */
+   glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
+   {
+      glPixelStorei(GL_PACK_ALIGNMENT, 1);
+      e = glGetError();
+      if (e) {
+         ALLEGRO_ERROR("glPixelStorei(GL_PACK_ALIGNMENT, %d) failed (%s).\n",
+            1, _al_gl_error_string(e));
+         ok = false;
+      }
+   }
+
+   if (ok) {
+      ogl_bitmap->lock_buffer = al_malloc(true_wc * true_hc * block_size);
+      
+      if (ogl_bitmap->lock_buffer != NULL) {
+         glBindTexture(GL_TEXTURE_2D, ogl_bitmap->texture);
+         glGetCompressedTexImage(GL_TEXTURE_2D, 0, ogl_bitmap->lock_buffer);
+         e = glGetError();
+         if (e) {
+            ALLEGRO_ERROR("glGetCompressedTexImage for format %s failed (%s).\n",
+               _al_pixel_format_name(bitmap_format), _al_gl_error_string(e));
+            al_free(ogl_bitmap->lock_buffer);
+            ogl_bitmap->lock_buffer = NULL;
+            ok = false;
+         }
+         else {
+            if (flags == ALLEGRO_LOCK_READWRITE) {
+               /* Need to make the locked memory contiguous, as
+                * glCompressedTexSubImage2D cannot read strided
+                * memory. */
+               int y;
+               int src_pitch = true_wc * block_size;
+               int dest_pitch = wc * block_size;
+               char* dest_ptr = (char*)ogl_bitmap->lock_buffer;
+               char* src_ptr = (char*)ogl_bitmap->lock_buffer
+                  + src_pitch * gl_yc + block_size * xc;
+               for (y = 0; y < hc; y++) {
+                  memmove(dest_ptr, src_ptr, dest_pitch);
+                  src_ptr += src_pitch;
+                  dest_ptr += dest_pitch;
+               }
+               bitmap->locked_region.data = ogl_bitmap->lock_buffer +
+                  dest_pitch * (hc - 1);
+               bitmap->locked_region.pitch = -dest_pitch;
+            }
+            else {
+               int pitch = true_wc * block_size;
+               bitmap->locked_region.data = ogl_bitmap->lock_buffer +
+                  pitch * (gl_yc + hc - 1) + block_size * xc;
+               bitmap->locked_region.pitch = -pitch;
+            }
+            bitmap->locked_region.format = bitmap_format;
+            bitmap->locked_region.pixel_size = block_size;
+         }
+      }
+      else {
+         ok = false;
+      }
+   }
+
+   glPopClientAttrib();
+
+   if (old_disp != NULL) {
+      _al_set_current_display_only(old_disp);
+   }
+
+   if (ok) {
+      ogl_flip_blocks(&bitmap->locked_region, wc, hc);
+      return &bitmap->locked_region;
+   }
+
+   ALLEGRO_ERROR("Failed to lock region\n");
+   ASSERT(ogl_bitmap->lock_buffer == NULL);
+   return NULL;
+}
+
+
+static void ogl_unlock_compressed_region(ALLEGRO_BITMAP *bitmap)
+{
+   ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap = bitmap->extra;
+   int lock_format = bitmap->locked_region.format;
+   ALLEGRO_DISPLAY *old_disp = NULL;
+   ALLEGRO_DISPLAY *disp;
+   GLenum e;
+   int block_size = al_get_pixel_block_size(lock_format);
+   int block_width = al_get_pixel_block_width(lock_format);
+   int data_size = bitmap->lock_h * bitmap->lock_w /
+      (block_width * block_width) * block_size;
+   int gl_y = _al_get_least_multiple(bitmap->h, block_width) - bitmap->lock_y - bitmap->lock_h;
+
+   if ((bitmap->lock_flags & ALLEGRO_LOCK_READONLY)) {
+      goto EXIT;
+   }
+
+   ogl_flip_blocks(&bitmap->locked_region, bitmap->lock_w / block_width,
+      bitmap->lock_h / block_width);
+
+   disp = al_get_current_display();
+
+   /* Change OpenGL context if necessary. */
+   if (!disp ||
+      (_al_get_bitmap_display(bitmap)->ogl_extras->is_shared == false &&
+       _al_get_bitmap_display(bitmap) != disp))
+   {
+      old_disp = disp;
+      _al_set_current_display_only(_al_get_bitmap_display(bitmap));
+   }
+
+   /* Keep this in sync with ogl_lock_compressed_region. */
+   glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
+   {
+      glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+      e = glGetError();
+      if (e) {
+         ALLEGRO_ERROR("glPixelStorei(GL_UNPACK_ALIGNMENT, %d) failed (%s).\n",
+            1, _al_gl_error_string(e));
+      }
+   }
+
+   glBindTexture(GL_TEXTURE_2D, ogl_bitmap->texture);
+   glCompressedTexSubImage2D(GL_TEXTURE_2D, 0,
+      bitmap->lock_x, gl_y,
+      bitmap->lock_w, bitmap->lock_h,
+      get_glformat(lock_format, 0),
+      data_size,
+      ogl_bitmap->lock_buffer);
+
+   e = glGetError();
+   if (e) {
+      ALLEGRO_ERROR("glCompressedTexSubImage2D for format %s failed (%s).\n",
+         _al_pixel_format_name(lock_format), _al_gl_error_string(e));
+   }
+
+   glPopClientAttrib();
+
+   if (old_disp) {
+      _al_set_current_display_only(old_disp);
+   }
+   
+EXIT:
+   al_free(ogl_bitmap->lock_buffer);
+   ogl_bitmap->lock_buffer = NULL;
+}
 
 
 /* Obtain a reference to this driver. */
@@ -603,6 +896,8 @@ static ALLEGRO_BITMAP_INTERFACE *ogl_bitmap_driver(void)
    glbmp_vt.lock_region = _al_ogl_lock_region_new;
    glbmp_vt.unlock_region = _al_ogl_unlock_region_new;
 #endif
+   glbmp_vt.lock_compressed_region = ogl_lock_compressed_region;
+   glbmp_vt.unlock_compressed_region = ogl_unlock_compressed_region;
 
    return &glbmp_vt;
 }
@@ -616,19 +911,33 @@ ALLEGRO_BITMAP *_al_ogl_create_bitmap(ALLEGRO_DISPLAY *d, int w, int h,
    ALLEGRO_BITMAP_EXTRA_OPENGL *extra;
    int true_w;
    int true_h;
-   int pitch;
+   int block_width;
    (void)d;
 
+   format = _al_get_real_pixel_format(d, format);
+   ASSERT(_al_pixel_format_is_real(format));
+
+   block_width = al_get_pixel_block_width(format);
+   true_w = _al_get_least_multiple(w, block_width);
+   true_h = _al_get_least_multiple(h, block_width);
+
+   if (_al_pixel_format_is_compressed(format)) {
+      if (!al_get_opengl_extension_list()->ALLEGRO_GL_EXT_texture_compression_s3tc) {
+         ALLEGRO_DEBUG("Device does not support compressed textures.");
+         return NULL;
+      }
+   }
+
    /* Android included because some devices require POT FBOs */
    if (!IS_OPENGLES &&
       d->extra_settings.settings[ALLEGRO_SUPPORT_NPOT_BITMAP])
    {
-      true_w = w;
-      true_h = h;
+      true_w = true_w;
+      true_h = true_h;
    }
    else {
-      true_w = pot(w);
-      true_h = pot(h);
+      true_w = pot(true_w);
+      true_h = pot(true_h);
    }
 
    /* This used to be an iOS/Android only workaround - but
@@ -648,11 +957,8 @@ ALLEGRO_BITMAP *_al_ogl_create_bitmap(ALLEGRO_DISPLAY *d, int w, int h,
       }
    }
 
-   format = _al_get_real_pixel_format(d, format);
-
-   ASSERT(_al_pixel_format_is_real(format));
-
-   pitch = true_w * al_get_pixel_size(format);
+   ASSERT(true_w % block_width == 0);
+   ASSERT(true_h % block_width == 0);
 
    bitmap = al_calloc(1, sizeof *bitmap);
    ASSERT(bitmap);
@@ -661,7 +967,9 @@ ALLEGRO_BITMAP *_al_ogl_create_bitmap(ALLEGRO_DISPLAY *d, int w, int h,
    extra = bitmap->extra;
 
    bitmap->vt = ogl_bitmap_driver();
-   bitmap->pitch = pitch;
+   bitmap->_memory_format = 
+      _al_pixel_format_is_compressed(format) ? ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE : format;
+   bitmap->pitch = true_w * al_get_pixel_size(bitmap->_memory_format);
    bitmap->_format = format;
    bitmap->_flags = flags | _ALLEGRO_INTERNAL_OPENGL;
 
@@ -669,7 +977,7 @@ ALLEGRO_BITMAP *_al_ogl_create_bitmap(ALLEGRO_DISPLAY *d, int w, int h,
    extra->true_h = true_h;
 
    if (!(flags & ALLEGRO_NO_PRESERVE_TEXTURE)) {
-      bitmap->memory = al_calloc(1, al_get_pixel_size(format)*w*h);
+      bitmap->memory = al_calloc(1, al_get_pixel_size(bitmap->_memory_format)*w*h);
    }
 
    return bitmap;
@@ -845,11 +1153,11 @@ void _al_opengl_backup_dirty_bitmaps(ALLEGRO_DISPLAY *d, bool flip)
       ALLEGRO_DEBUG("Backing up dirty bitmap %p\n", b);
       lr = al_lock_bitmap(
          b,
-         ALLEGRO_PIXEL_FORMAT_ANY,
+         _al_get_bitmap_memory_format(b),
          ALLEGRO_LOCK_READONLY
       );
       if (lr) {
-         int line_size = al_get_pixel_size(al_get_bitmap_format(b)) * b->w;
+         int line_size = al_get_pixel_size(lr->format) * b->w;
          for (y = 0; y < b->h; y++) {
             unsigned char *p = ((unsigned char *)lr->data) + lr->pitch * y;
             unsigned char *p2;
diff --git a/src/opengl/ogl_lock.c b/src/opengl/ogl_lock.c
index fba1df3..c7d8353 100644
--- a/src/opengl/ogl_lock.c
+++ b/src/opengl/ogl_lock.c
@@ -102,7 +102,16 @@ ALLEGRO_LOCKED_REGION *_al_ogl_lock_region_new(ALLEGRO_BITMAP *bitmap,
    bool ok;
 
    if (format == ALLEGRO_PIXEL_FORMAT_ANY) {
-      format = al_get_bitmap_format(bitmap);
+      /* Never pick compressed formats with ANY, as it interacts weirdly with
+       * existing code (e.g. al_get_pixel_size() etc) */
+      int bitmap_format = al_get_bitmap_format(bitmap);
+      if (_al_pixel_format_is_compressed(bitmap_format)) {
+         // XXX Get a good format from the driver?
+         format = ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE;
+      }
+      else {
+         format = bitmap_format;
+      }
    }
 
    disp = al_get_current_display();
diff --git a/src/opengl/ogl_lock_es.c b/src/opengl/ogl_lock_es.c
index 34fa2a5..777a954 100644
--- a/src/opengl/ogl_lock_es.c
+++ b/src/opengl/ogl_lock_es.c
@@ -106,7 +106,16 @@ ALLEGRO_LOCKED_REGION *_al_ogl_lock_region_gles(ALLEGRO_BITMAP *bitmap,
    int real_format;
 
    if (format == ALLEGRO_PIXEL_FORMAT_ANY) {
-      format = al_get_bitmap_format(bitmap);
+      /* Never pick compressed formats with ANY, as it interacts weirdly with
+       * existing code (e.g. al_get_pixel_size() etc) */
+      int bitmap_format = al_get_bitmap_format(bitmap);
+      if (_al_pixel_format_is_compressed(bitmap_format)) {
+         // XXX Get a good format from the driver?
+         format = ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE;
+      }
+      else {
+         format = bitmap_format;
+      }
    }
 
    disp = al_get_current_display();
diff --git a/src/pixels.c b/src/pixels.c
index a988b39..542040c 100644
--- a/src/pixels.c
+++ b/src/pixels.c
@@ -57,6 +57,9 @@ static int pixel_sizes[] = {
    4, /* ALLEGRO_PIXEL_FORMAT_ABGR_LE */
    2, /* ALLEGRO_PIXEL_FORMAT_RGBA_4444 */
    1, /* ALLEGRO_PIXEL_FORMAT_SINGLE_CHANNEL_8 */
+   0,
+   0,
+   0,
 };
 
 static int pixel_bits[] = {
@@ -88,6 +91,77 @@ static int pixel_bits[] = {
    32, /* ALLEGRO_PIXEL_FORMAT_ABGR_LE */
    16, /* ALLEGRO_PIXEL_FORMAT_RGBA_4444 */
    8, /* ALLEGRO_PIXEL_FORMAT_SINGLE_CHANNEL_8 */
+   0,
+   0,
+   0,
+};
+
+static int pixel_block_widths[] = {
+   0, /* ALLEGRO_PIXEL_FORMAT_ANY */
+   0,
+   0,
+   1,
+   1,
+   1,
+   1,
+   1,
+   1,
+   1, /* ALLEGRO_PIXEL_FORMAT_ARGB_8888 */
+   1,
+   1,
+   1,
+   1,
+   1,
+   1,
+   1,
+   1,
+   1,
+   1,
+   1,
+   1,
+   1,
+   1,
+   1, /* ALLEGRO_PIXEL_FORMAT_ABGR_F32 */
+   1, /* ALLEGRO_PIXEL_FORMAT_ABGR_LE */
+   1, /* ALLEGRO_PIXEL_FORMAT_RGBA_4444 */
+   1, /* ALLEGRO_PIXEL_FORMAT_SINGLE_CHANNEL_8 */
+   4,
+   4,
+   4,
+};
+
+static int pixel_block_sizes[] = {
+   0,  /* ALLEGRO_PIXEL_FORMAT_ANY */
+   0,
+   0,
+   2,
+   2,
+   2,
+   3,
+   4,
+   4,
+   4,  /* ALLEGRO_PIXEL_FORMAT_ARGB_8888 */
+   4,
+   2,
+   3,
+   2,
+   2,
+   2,
+   2,
+   4,
+   4,
+   3,
+   2,
+   2,
+   4,
+   4,
+   16, /* ALLEGRO_PIXEL_FORMAT_ABGR_F32 */
+   4,  /* ALLEGRO_PIXEL_FORMAT_ABGR_LE */
+   2,  /* ALLEGRO_PIXEL_FORMAT_RGBA_4444 */
+   1,  /* ALLEGRO_PIXEL_FORMAT_SINGLE_CHANNEL_8 */
+   8,
+   16,
+   16,
 };
 
 static bool format_alpha_table[ALLEGRO_NUM_PIXEL_FORMATS] = {
@@ -119,6 +193,9 @@ static bool format_alpha_table[ALLEGRO_NUM_PIXEL_FORMATS] = {
    true, /* ALLEGRO_PIXEL_FORMAT_ABGR_LE */
    true, /* ALLEGRO_PIXEL_FORMAT_RGBA_4444 */
    false, /* ALLEGRO_PIXEL_FORMAT_SINGLE_CHANNEL_8 */
+   true,
+   true,
+   true,
 };
 
 static char const *pixel_format_names[ALLEGRO_NUM_PIXEL_FORMATS + 1] = {
@@ -150,6 +227,9 @@ static char const *pixel_format_names[ALLEGRO_NUM_PIXEL_FORMATS + 1] = {
    "ABGR_8888_LE",
    "RGBA_4444",
    "SINGLE_CHANNEL_8",
+   "RGBA_DXT1",
+   "RGBA_DXT3",
+   "RGBA_DXT5",
    "INVALID"
 };
 
@@ -183,6 +263,79 @@ static bool format_is_real[ALLEGRO_NUM_PIXEL_FORMATS] =
    true, /* ALLEGRO_PIXEL_FORMAT_ABGR_LE */
    true, /* ALLEGRO_PIXEL_FORMAT_RGBA_4444 */
    true, /* ALLEGRO_PIXEL_FORMAT_SINGLE_CHANNEL_8 */
+   true,
+   true,
+   true,
+};
+
+static bool format_is_video_only[ALLEGRO_NUM_PIXEL_FORMATS] =
+{
+   false, /* ALLEGRO_PIXEL_FORMAT_ANY */
+   false,
+   false,
+   false,
+   false,
+   false,
+   false,
+   false,
+   false,
+   false, /* ALLEGRO_PIXEL_FORMAT_ARGB_8888 */
+   false,
+   false,
+   false,
+   false,
+   false,
+   false,
+   false,
+   false,
+   false,
+   false,
+   false,
+   false,
+   false,
+   false,
+   false, /* ALLEGRO_PIXEL_FORMAT_ABGR_F32 */
+   false, /* ALLEGRO_PIXEL_FORMAT_ABGR_LE */
+   false, /* ALLEGRO_PIXEL_FORMAT_RGBA_4444 */
+   false, /* ALLEGRO_PIXEL_FORMAT_SINGLE_CHANNEL_8 */
+   true,
+   true,
+   true,
+};
+
+static bool format_is_compressed[ALLEGRO_NUM_PIXEL_FORMATS] =
+{
+   false, /* ALLEGRO_PIXEL_FORMAT_ANY */
+   false,
+   false,
+   false,
+   false,
+   false,
+   false,
+   false,
+   false,
+   false, /* ALLEGRO_PIXEL_FORMAT_ARGB_8888 */
+   false,
+   false,
+   false,
+   false,
+   false,
+   false,
+   false,
+   false,
+   false,
+   false,
+   false,
+   false,
+   false,
+   false,
+   false, /* ALLEGRO_PIXEL_FORMAT_ABGR_F32 */
+   false, /* ALLEGRO_PIXEL_FORMAT_ABGR_LE */
+   false, /* ALLEGRO_PIXEL_FORMAT_RGBA_4444 */
+   false, /* ALLEGRO_PIXEL_FORMAT_SINGLE_CHANNEL_8 */
+   true,
+   true,
+   true,
 };
 
 
@@ -206,6 +359,22 @@ void _al_init_pixels(void)
 }
 
 
+/* Function: al_get_pixel_block_size
+ */
+int al_get_pixel_block_size(int format)
+{
+   return pixel_block_sizes[format];
+}
+
+
+/* Function: al_get_pixel_block_width
+ */
+int al_get_pixel_block_width(int format)
+{
+   return pixel_block_widths[format];
+}
+
+
 /* Function: al_get_pixel_size
  */
 int al_get_pixel_size(int format)
@@ -236,6 +405,22 @@ bool _al_pixel_format_is_real(int format)
    return format_is_real[format];
 }
 
+bool _al_pixel_format_is_video_only(int format)
+{
+   ASSERT(format >= 0);
+   ASSERT(format < ALLEGRO_NUM_PIXEL_FORMATS);
+
+   return format_is_video_only[format];
+}
+
+bool _al_pixel_format_is_compressed(int format)
+{
+   ASSERT(format >= 0);
+   ASSERT(format < ALLEGRO_NUM_PIXEL_FORMATS);
+
+   return format_is_compressed[format];
+}
+
 
 /* We use al_get_display_format() as a hint for the preferred RGB ordering when
  * nothing else is specified.
diff --git a/src/tri_soft.c b/src/tri_soft.c
index 7a2a640..42ca370 100644
--- a/src/tri_soft.c
+++ b/src/tri_soft.c
@@ -829,7 +829,8 @@ void _al_draw_soft_triangle(
       min_y = clip_min_y;
 
    if (al_is_bitmap_locked(target)) {
-      if (!bitmap_region_is_locked(target, min_x, min_y, max_x - min_x, max_y - min_y))
+      if (!bitmap_region_is_locked(target, min_x, min_y, max_x - min_x, max_y - min_y)
+            || _al_pixel_format_is_video_only(target->locked_region.format))
          return;
    } else {
       if (!(lr = al_lock_bitmap_region(target, min_x, min_y, max_x - min_x, max_y - min_y, ALLEGRO_PIXEL_FORMAT_ANY, 0)))
diff --git a/src/win/d3d_bmp.cpp b/src/win/d3d_bmp.cpp
index 1b11e84..16aa9b9 100644
--- a/src/win/d3d_bmp.cpp
+++ b/src/win/d3d_bmp.cpp
@@ -40,6 +40,56 @@ static ALLEGRO_BITMAP_INTERFACE *vt;
 #define get_extra(b) ((ALLEGRO_BITMAP_EXTRA_D3D *)\
    (b->parent ? b->parent->extra : b->extra))
 
+static bool convert_compressed(LPDIRECT3DTEXTURE9 dest, LPDIRECT3DTEXTURE9 src,
+   int x, int y, int width, int height) {
+   bool ok = true;
+   LPDIRECT3DSURFACE9 dest_texture_surface = NULL;
+   LPDIRECT3DSURFACE9 src_texture_surface = NULL;
+
+   if (dest->GetSurfaceLevel(
+         0, &dest_texture_surface) != D3D_OK) {
+      ALLEGRO_ERROR("convert_compressed: GetSurfaceLevel failed on dest.\n");
+      ok = false;
+   }
+
+   if (ok && src->GetSurfaceLevel(
+         0, &src_texture_surface) != D3D_OK) {
+      ALLEGRO_ERROR("convert_compressed: GetSurfaceLevel failed on src.\n");
+      ok = false;
+   }
+
+   RECT rect;
+   rect.left = x;
+   rect.top = y;
+   rect.right = x + width;
+   rect.bottom = y + height;
+
+   if (ok && _al_imp_D3DXLoadSurfaceFromSurface(
+         dest_texture_surface,
+         NULL,
+         &rect,
+         src_texture_surface,
+         NULL,
+         &rect,
+         D3DX_FILTER_NONE,
+         0) != D3D_OK) {
+      ALLEGRO_ERROR("convert_compressed: D3DXLoadSurfaceFromSurface failed.\n");
+   }
+
+   int i;
+   if (src_texture_surface) {
+       if ((i = src_texture_surface->Release()) != 0) {
+          ALLEGRO_DEBUG("convert_compressed (src) ref count == %d\n", i);
+       }
+   }
+   if (dest_texture_surface) {
+       if ((i = dest_texture_surface->Release()) != 0) {
+          // This can be non-zero
+          ALLEGRO_DEBUG("convert_compressed (dest) ref count == %d\n", i);
+       }
+   }
+   return ok;
+}
 
 /* Function: al_get_d3d_texture_size
  */
@@ -166,12 +216,12 @@ static void d3d_draw_textured_quad(
    bool pp = (aldisp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) != 0;
 
    if (pp) {
-   	ALLEGRO_VERTEX *vertices = (ALLEGRO_VERTEX *)aldisp->vt->prepare_vertex_cache(aldisp, 6);
-	SET(ALLEGRO_COLOR)
+           ALLEGRO_VERTEX *vertices = (ALLEGRO_VERTEX *)aldisp->vt->prepare_vertex_cache(aldisp, 6);
+        SET(ALLEGRO_COLOR)
    }
    else {
-   	D3D_FIXED_VERTEX *vertices = (D3D_FIXED_VERTEX *)aldisp->vt->prepare_vertex_cache(aldisp, 6);
-	SET(ALLEGRO_COLOR_TO_D3D)
+           D3D_FIXED_VERTEX *vertices = (D3D_FIXED_VERTEX *)aldisp->vt->prepare_vertex_cache(aldisp, 6);
+        SET(ALLEGRO_COLOR_TO_D3D)
    }
 
    if (!aldisp->cache_enabled)
@@ -186,15 +236,21 @@ static void d3d_sync_bitmap_memory(ALLEGRO_BITMAP *bitmap)
    LPDIRECT3DTEXTURE9 texture;
    int bitmap_format = al_get_bitmap_format(bitmap);
 
-   if (_al_d3d_render_to_texture_supported())
+   if (_al_d3d_render_to_texture_supported()
+      && !_al_pixel_format_is_compressed(bitmap_format))
       texture = d3d_bmp->system_texture;
    else
       texture = d3d_bmp->video_texture;
 
    if (texture->LockRect(0, &locked_rect, NULL, 0) == D3D_OK) {
-      _al_convert_bitmap_data(locked_rect.pBits, bitmap_format, locked_rect.Pitch,
-         bitmap->memory, bitmap_format, al_get_pixel_size(bitmap_format)*bitmap->w,
-         0, 0, 0, 0, bitmap->w, bitmap->h);
+      int block_size = al_get_pixel_block_size(bitmap_format);
+      int block_width = al_get_pixel_block_width(bitmap_format);
+      int mem_pitch = _al_get_least_multiple(bitmap->w, block_width)
+         * block_size / block_width;
+      _al_copy_bitmap_data(locked_rect.pBits, locked_rect.Pitch,
+         bitmap->memory, mem_pitch,
+         0, 0, 0, 0, _al_get_least_multiple(bitmap->w, block_width),
+         _al_get_least_multiple(bitmap->h, block_width), bitmap_format);
       texture->UnlockRect(0);
    }
    else {
@@ -219,47 +275,21 @@ static void d3d_sync_bitmap_texture(ALLEGRO_BITMAP *bitmap,
    rect.right = x + width;
    rect.bottom = y + height;
 
-   if (_al_d3d_render_to_texture_supported())
+   if (_al_d3d_render_to_texture_supported()
+         && !_al_pixel_format_is_compressed(bitmap_format))
       texture = d3d_bmp->system_texture;
    else
       texture = d3d_bmp->video_texture;
 
    if (texture->LockRect(0, &locked_rect, &rect, 0) == D3D_OK) {
-	   _al_convert_bitmap_data(bitmap->memory, bitmap_format, bitmap->w*al_get_pixel_size(bitmap_format),
-		  locked_rect.pBits, bitmap_format, locked_rect.Pitch,
-		  x, y, 0, 0, width, height);
-	   /* Copy an extra row and column so the texture ends nicely */
-	   if (rect.bottom > bitmap->h) {
-		  _al_convert_bitmap_data(
-			 bitmap->memory,
-			 bitmap_format, bitmap->w*al_get_pixel_size(bitmap_format),
-			 locked_rect.pBits,
-			 bitmap_format, locked_rect.Pitch,
-			 0, bitmap->h-1,
-			 0, height,
-			 width, 1);
-	   }
-	   if (rect.right > bitmap->w) {
-		  _al_convert_bitmap_data(
-			 bitmap->memory,
-			 bitmap_format, bitmap->w*al_get_pixel_size(bitmap_format),
-			 locked_rect.pBits,
-			 bitmap_format, locked_rect.Pitch,
-			 bitmap->w-1, 0,
-			 width, 0,
-			 1, height);
-	   }
-	   if (rect.bottom > bitmap->h && rect.right > bitmap->w) {
-		  _al_convert_bitmap_data(
-			 bitmap->memory,
-			 bitmap_format, bitmap->w*al_get_pixel_size(bitmap_format),
-			 locked_rect.pBits,
-			 bitmap_format, locked_rect.Pitch,
-			 bitmap->w-1, bitmap->h-1,
-			 width, height,
-			 1, 1);
-	   }
-	   texture->UnlockRect(0);
+      int block_size = al_get_pixel_block_size(bitmap_format);
+      int block_width = al_get_pixel_block_width(bitmap_format);
+      int mem_pitch = _al_get_least_multiple(bitmap->w, block_width)
+         * block_size / block_width;
+      _al_copy_bitmap_data(bitmap->memory, mem_pitch,
+         locked_rect.pBits, locked_rect.Pitch,
+         x, y, 0, 0, width, height, bitmap_format);
+      texture->UnlockRect(0);
    }
    else {
       ALLEGRO_ERROR("d3d_sync_bitmap_texture: Couldn't lock texture to upload.\n");
@@ -269,16 +299,16 @@ static void d3d_sync_bitmap_texture(ALLEGRO_BITMAP *bitmap,
 static void d3d_do_upload(ALLEGRO_BITMAP *bmp, int x, int y, int width,
    int height, bool sync_from_memory)
 {
-   ALLEGRO_BITMAP_EXTRA_D3D *d3d_bmp = get_extra(bmp);
-
    if (sync_from_memory) {
       d3d_sync_bitmap_texture(bmp, x, y, width, height);
    }
 
-   if (_al_d3d_render_to_texture_supported()) {
-      if (d3d_bmp->display->device->UpdateTexture(
-            (IDirect3DBaseTexture9 *)d3d_bmp->system_texture,
-            (IDirect3DBaseTexture9 *)d3d_bmp->video_texture) != D3D_OK) {
+   if (_al_d3d_render_to_texture_supported()
+         && !_al_pixel_format_is_compressed(al_get_bitmap_format(bmp))) {
+      ALLEGRO_BITMAP_EXTRA_D3D *d3d_bitmap = get_extra(bmp);
+      if (d3d_bitmap->display->device->UpdateTexture(
+            (IDirect3DBaseTexture9 *)d3d_bitmap->system_texture,
+            (IDirect3DBaseTexture9 *)d3d_bitmap->video_texture) != D3D_OK) {
          ALLEGRO_ERROR("d3d_do_upload: Couldn't update texture.\n");
          return;
       }
@@ -315,11 +345,12 @@ void _al_d3d_release_default_pool_textures(ALLEGRO_DISPLAY *disp)
 static bool d3d_create_textures(ALLEGRO_DISPLAY_D3D *disp, int w, int h,
    int flags,
    LPDIRECT3DTEXTURE9 *video_texture, LPDIRECT3DTEXTURE9 *system_texture,
-   int format)
+   int video_format, int system_format)
 {
    int levels;
    int autogenmipmap;
    int err;
+   bool compressed = _al_pixel_format_is_compressed(video_format);
 
    if (flags & ALLEGRO_MIPMAP) {
       /* "0" for all possible levels, required for auto mipmap generation. */
@@ -333,9 +364,16 @@ static bool d3d_create_textures(ALLEGRO_DISPLAY_D3D *disp, int w, int h,
 
    if (_al_d3d_render_to_texture_supported()) {
       if (video_texture) {
+         int usage = compressed ? 0 : D3DUSAGE_RENDERTARGET;
+         /* XXX: Compressed video bitmaps are managed, so in principle
+          * there is no need to manually sync them for device loss.
+          * It is still necessary to do so for resizing purposes,
+          * however... not sure there's any real savings to be had here.
+          */
+         D3DPOOL pool = compressed ? D3DPOOL_MANAGED : D3DPOOL_DEFAULT;
          err = disp->device->CreateTexture(w, h, levels,
-            D3DUSAGE_RENDERTARGET | autogenmipmap,
-            (D3DFORMAT)_al_pixel_format_to_d3d(format), D3DPOOL_DEFAULT,
+            usage | autogenmipmap,
+            (D3DFORMAT)_al_pixel_format_to_d3d(video_format), pool,
             video_texture, NULL);
          if (err != D3D_OK && err != D3DOK_NOAUTOGEN) {
             ALLEGRO_ERROR("d3d_create_textures: Unable to create video texture.\n");
@@ -345,7 +383,7 @@ static bool d3d_create_textures(ALLEGRO_DISPLAY_D3D *disp, int w, int h,
 
       if (system_texture) {
          err = disp->device->CreateTexture(w, h, 1,
-            0, (D3DFORMAT)_al_pixel_format_to_d3d(format), D3DPOOL_SYSTEMMEM,
+            0, (D3DFORMAT)_al_pixel_format_to_d3d(system_format), D3DPOOL_SYSTEMMEM,
             system_texture, NULL);
          if (err != D3D_OK) {
             ALLEGRO_ERROR("d3d_create_textures: Unable to create system texture.\n");
@@ -362,7 +400,7 @@ static bool d3d_create_textures(ALLEGRO_DISPLAY_D3D *disp, int w, int h,
    else {
       if (video_texture) {
          err = disp->device->CreateTexture(w, h, 1,
-            0, (D3DFORMAT)_al_pixel_format_to_d3d(format), D3DPOOL_MANAGED,
+            0, (D3DFORMAT)_al_pixel_format_to_d3d(video_format), D3DPOOL_MANAGED,
             video_texture, NULL);
          if (err != D3D_OK) {
             ALLEGRO_ERROR("d3d_create_textures: Unable to create video texture (no render-to-texture).\n");
@@ -384,6 +422,7 @@ static ALLEGRO_BITMAP
    D3DLOCKED_RECT surf_locked_rect;
    D3DLOCKED_RECT sys_locked_rect;
    unsigned int y;
+   ASSERT(!_al_pixel_format_is_compressed(format));
 
    if (surface->GetDesc(&desc) != D3D_OK) {
       ALLEGRO_ERROR("d3d_create_bitmap_from_surface: GetDesc failed.\n");
@@ -422,10 +461,11 @@ static ALLEGRO_BITMAP
    surface->UnlockRect();
    extra->system_texture->UnlockRect(0);
 
+
    if (extra->display->device->UpdateTexture(
          (IDirect3DBaseTexture9 *)extra->system_texture,
          (IDirect3DBaseTexture9 *)extra->video_texture) != D3D_OK) {
-      ALLEGRO_ERROR("d3d_create_bitmap_from_texture: Couldn't update texture.\n");
+      ALLEGRO_ERROR("d3d_create_bitmap_from_surface: Couldn't update texture.\n");
    }
 
    return bitmap;
@@ -467,13 +507,13 @@ static bool _al_d3d_sync_bitmap(ALLEGRO_BITMAP *dest)
 
    if (d3d_dest->system_texture->GetSurfaceLevel(
          0, &system_texture_surface) != D3D_OK) {
-      ALLEGRO_ERROR("_al_d3d_sync_bitmap: GetSurfaceLevel failed while updating video texture.\n");
+      ALLEGRO_ERROR("_al_d3d_sync_bitmap: GetSurfaceLevel failed while updating system texture.\n");
       ok = false;
    }
 
    if (ok && d3d_dest->video_texture->GetSurfaceLevel(
          0, &video_texture_surface) != D3D_OK) {
-      ALLEGRO_ERROR("_al_d3d_sync_bitmap: GetSurfaceLevel failed while updating video texture.\n");
+      ALLEGRO_ERROR("_al_d3d_sync_bitmap: GetSurfaceLevel failed while updating system texture.\n");
       ok = false;
    }
 
@@ -486,13 +526,13 @@ static bool _al_d3d_sync_bitmap(ALLEGRO_BITMAP *dest)
 
    if (system_texture_surface) {
        if ((i = system_texture_surface->Release()) != 0) {
-	  ALLEGRO_DEBUG("_al_d3d_sync_bitmap (system) ref count == %d\n", i);
+          ALLEGRO_DEBUG("_al_d3d_sync_bitmap (system) ref count == %d\n", i);
        }
    }
    if (video_texture_surface) {
        if ((i = video_texture_surface->Release()) != 0) {
-	  // This can be non-zero
-	  ALLEGRO_DEBUG("_al_d3d_sync_bitmap (video) ref count == %d\n", i);
+          // This can be non-zero
+          ALLEGRO_DEBUG("_al_d3d_sync_bitmap (video) ref count == %d\n", i);
        }
    }
 
@@ -529,11 +569,14 @@ void _al_d3d_prepare_bitmaps_for_reset(ALLEGRO_DISPLAY_D3D *disp)
       if ((void *)_al_get_bitmap_display(bmp) == (void *)disp) {
          if ((bitmap_flags & ALLEGRO_MEMORY_BITMAP) ||
             (bitmap_flags & ALLEGRO_NO_PRESERVE_TEXTURE) ||
-   	    !bmp->dirty ||
-   	    extra->is_backbuffer ||
-	    bmp->parent)
-	    continue;
-         _al_d3d_sync_bitmap(bmp);
+               !bmp->dirty ||
+               extra->is_backbuffer ||
+            bmp->parent)
+            continue;
+         if (_al_pixel_format_is_compressed(al_get_bitmap_format(bmp)))
+            d3d_sync_bitmap_memory(bmp);
+         else
+            _al_d3d_sync_bitmap(bmp);
          bmp->dirty = false;
       }
    }
@@ -555,14 +598,19 @@ bool _al_d3d_recreate_bitmap_textures(ALLEGRO_DISPLAY_D3D *disp)
       ALLEGRO_BITMAP_EXTRA_D3D *extra = get_extra(bmp);
 
       if ((void *)_al_get_bitmap_display(bmp) == (void *)disp) {
-	      if (!d3d_create_textures(disp, extra->texture_w,
+         int block_width =
+            al_get_pixel_block_size(al_get_bitmap_format(bmp));
+         if (!d3d_create_textures(disp, extra->texture_w,
             extra->texture_h,
             al_get_bitmap_flags(bmp),
             &extra->video_texture,
             &extra->system_texture,
-            al_get_bitmap_format(bmp)))
+            al_get_bitmap_format(bmp),
+            extra->system_format))
             return false;
-	      d3d_do_upload(bmp, 0, 0, bmp->w, bmp->h, true);
+         d3d_do_upload(bmp, 0, 0,
+            _al_get_least_multiple(bmp->w, block_width),
+            _al_get_least_multiple(bmp->h, block_width), true);
       }
    }
 
@@ -592,13 +640,17 @@ void _al_d3d_refresh_texture_memory(ALLEGRO_DISPLAY *display)
 
       d3d_create_textures(bmps_display, extra->texture_w,
          extra->texture_h, bitmap_flags,
-         &extra->video_texture, /*&bmp->system_texture*/0, al_get_bitmap_format(bmp));
+         &extra->video_texture, /*&bmp->system_texture*/0, al_get_bitmap_format(bmp), 0);
       if (!(bitmap_flags & ALLEGRO_NO_PRESERVE_TEXTURE)) {
+         int block_width = al_get_pixel_block_width(al_get_bitmap_format(bmp));
          d3d_sync_bitmap_texture(bmp,
-	    0, 0, bmp->w, bmp->h);
-         if (_al_d3d_render_to_texture_supported()) {
-	    bmps_display->device->UpdateTexture(
-	       (IDirect3DBaseTexture9 *)extra->system_texture,
+            0, 0,
+            _al_get_least_multiple(bmp->w, block_width),
+            _al_get_least_multiple(bmp->h, block_width));
+         if (_al_d3d_render_to_texture_supported()
+               && !_al_pixel_format_is_compressed(al_get_bitmap_format(bmp))) {
+            extra->display->device->UpdateTexture(
+               (IDirect3DBaseTexture9 *)extra->system_texture,
                (IDirect3DBaseTexture9 *)extra->video_texture);
          }
       }
@@ -608,8 +660,11 @@ void _al_d3d_refresh_texture_memory(ALLEGRO_DISPLAY *display)
 static bool d3d_upload_bitmap(ALLEGRO_BITMAP *bitmap)
 {
    ALLEGRO_BITMAP_EXTRA_D3D *d3d_bmp = get_extra(bitmap);
-   int w = bitmap->w;
-   int h = bitmap->h;
+   int bitmap_format = al_get_bitmap_format(bitmap);
+   int system_format = d3d_bmp->system_format;
+   int block_width = al_get_pixel_block_width(bitmap_format);
+   int w = _al_get_least_multiple(bitmap->w, block_width);
+   int h = _al_get_least_multiple(bitmap->h, block_width);
 
    if (d3d_bmp->display->device_lost)
       return false;
@@ -639,6 +694,9 @@ static bool d3d_upload_bitmap(ALLEGRO_BITMAP *bitmap)
       if (d3d_bmp->texture_w < 16) d3d_bmp->texture_w = 16;
       if (d3d_bmp->texture_h < 16) d3d_bmp->texture_h = 16;
 
+      ASSERT(d3d_bmp->texture_w % block_width == 0);
+      ASSERT(d3d_bmp->texture_h % block_width == 0);
+
       if (d3d_bmp->video_texture == 0)
          if (!d3d_create_textures(d3d_bmp->display,
                d3d_bmp->texture_w,
@@ -646,7 +704,8 @@ static bool d3d_upload_bitmap(ALLEGRO_BITMAP *bitmap)
                al_get_bitmap_flags(bitmap),
                &d3d_bmp->video_texture,
                &d3d_bmp->system_texture,
-               al_get_bitmap_format(bitmap))) {
+               bitmap_format,
+               system_format)) {
             return false;
          }
 
@@ -700,34 +759,34 @@ static void d3d_draw_bitmap_region(
       else {
          RECT r;
          if (d3d_src->display->device->CreateRenderTarget(
-		desc.Width,
-		desc.Height,
-		desc.Format,
-		D3DMULTISAMPLE_NONE,
-		0,
-		TRUE,
-		&surface,
-		NULL
-	) != D3D_OK) {
+                desc.Width,
+                desc.Height,
+                desc.Format,
+                D3DMULTISAMPLE_NONE,
+                0,
+                TRUE,
+                &surface,
+                NULL
+        ) != D3D_OK) {
             ALLEGRO_ERROR(
-	    	"d3d_draw_bitmap_region: CreateRenderTarget failed.\n");
+                    "d3d_draw_bitmap_region: CreateRenderTarget failed.\n");
+            return;
+         }
+         r.top = 0;
+         r.left = 0;
+         r.right = desc.Width;
+         r.bottom = desc.Height;
+         if (d3d_src->display->device->StretchRect(
+                d3d_src->display->render_target,
+                &r,
+                surface,
+                &r,
+                D3DTEXF_NONE
+         ) != D3D_OK) {
+            ALLEGRO_ERROR("d3d_draw_bitmap_region: StretchRect failed.\n");
+            surface->Release();
             return;
          }
-	 r.top = 0;
-	 r.left = 0;
-	 r.right = desc.Width;
-	 r.bottom = desc.Height;
-	 if (d3d_src->display->device->StretchRect(
-		d3d_src->display->render_target,
-		&r,
-		surface,
-		&r,
-		D3DTEXF_NONE
-	 ) != D3D_OK) {
-	    ALLEGRO_ERROR("d3d_draw_bitmap_region: StretchRect failed.\n");
-	    surface->Release();
-	    return;
-	 }
       }
       ALLEGRO_BITMAP *tmp_bmp = d3d_create_bitmap_from_surface(
          surface,
@@ -738,9 +797,9 @@ static void d3d_draw_bitmap_region(
          d3d_draw_bitmap_region(tmp_bmp, tint,
             sx, sy, sw, sh, flags);
          al_destroy_bitmap(tmp_bmp);
-	 if (desc.MultiSampleType != D3DMULTISAMPLE_NONE) {
-	    surface->Release();
-	 }
+         if (desc.MultiSampleType != D3DMULTISAMPLE_NONE) {
+            surface->Release();
+         }
       }
       return;
    }
@@ -758,6 +817,7 @@ static ALLEGRO_LOCKED_REGION *d3d_lock_region(ALLEGRO_BITMAP *bitmap,
 {
    ALLEGRO_BITMAP_EXTRA_D3D *d3d_bmp = get_extra(bitmap);
    int bitmap_format = al_get_bitmap_format(bitmap);
+   int system_format = d3d_bmp->system_format;
    
    if (d3d_bmp->display->device_lost)
       return NULL;
@@ -784,15 +844,26 @@ static ALLEGRO_LOCKED_REGION *d3d_lock_region(ALLEGRO_BITMAP *bitmap,
    }
    else {
       LPDIRECT3DTEXTURE9 texture;
-      if (_al_d3d_render_to_texture_supported()) {
+      if (_al_pixel_format_is_compressed(bitmap_format)) {
+         if (!(flags & ALLEGRO_LOCK_WRITEONLY)) {
+            if(!convert_compressed(
+                  d3d_bmp->system_texture, d3d_bmp->video_texture,
+                  x, y, w, h)) {
+               ALLEGRO_ERROR("Could not decompress.\n");
+               return NULL;
+            }
+         }
+         texture = d3d_bmp->system_texture;
+      }
+      else if (_al_d3d_render_to_texture_supported()) {
          /* 
-	  * Sync bitmap->memory with texture
+          * Sync bitmap->memory with texture
           */
-	 bitmap->locked = false;
+         bitmap->locked = false;
          if (!_al_d3d_sync_bitmap(bitmap)) {
             return NULL;
          }
-	 bitmap->locked = true;
+         bitmap->locked = true;
          texture = d3d_bmp->system_texture;
       }
       else {
@@ -804,20 +875,20 @@ static ALLEGRO_LOCKED_REGION *d3d_lock_region(ALLEGRO_BITMAP *bitmap,
       }
    }
 
-   if (format == ALLEGRO_PIXEL_FORMAT_ANY || bitmap_format == format || bitmap_format == f) {
+   if (format == ALLEGRO_PIXEL_FORMAT_ANY || system_format == format || system_format == f) {
       bitmap->locked_region.data = d3d_bmp->locked_rect.pBits;
-      bitmap->locked_region.format = bitmap_format;
+      bitmap->locked_region.format = system_format;
       bitmap->locked_region.pitch = d3d_bmp->locked_rect.Pitch;
-      bitmap->locked_region.pixel_size = al_get_pixel_size(bitmap_format);
+      bitmap->locked_region.pixel_size = al_get_pixel_size(system_format);
    }
    else {
       bitmap->locked_region.pitch = al_get_pixel_size(f) * w;
       bitmap->locked_region.data = al_malloc(bitmap->locked_region.pitch*h);
       bitmap->locked_region.format = f;
-      bitmap->locked_region.pixel_size = al_get_pixel_size(bitmap_format);
+      bitmap->locked_region.pixel_size = al_get_pixel_size(f);
       if (!(bitmap->lock_flags & ALLEGRO_LOCK_WRITEONLY)) {
          _al_convert_bitmap_data(
-            d3d_bmp->locked_rect.pBits, bitmap_format, d3d_bmp->locked_rect.Pitch,
+            d3d_bmp->locked_rect.pBits, system_format, d3d_bmp->locked_rect.Pitch,
             bitmap->locked_region.data, f, bitmap->locked_region.pitch,
             0, 0, 0, 0, w, h);
       }
@@ -829,13 +900,13 @@ static ALLEGRO_LOCKED_REGION *d3d_lock_region(ALLEGRO_BITMAP *bitmap,
 static void d3d_unlock_region(ALLEGRO_BITMAP *bitmap)
 {
    ALLEGRO_BITMAP_EXTRA_D3D *d3d_bmp = get_extra(bitmap);
-   int bitmap_format = al_get_bitmap_format(bitmap);
+   int system_format = d3d_bmp->system_format;
 
-   if (bitmap->locked_region.format != 0 && bitmap->locked_region.format != bitmap_format) {
+   if (bitmap->locked_region.format != 0 && bitmap->locked_region.format != system_format) {
       if (!(bitmap->lock_flags & ALLEGRO_LOCK_READONLY)) {
          _al_convert_bitmap_data(
             bitmap->locked_region.data, bitmap->locked_region.format, bitmap->locked_region.pitch,
-            d3d_bmp->locked_rect.pBits, bitmap_format, d3d_bmp->locked_rect.Pitch,
+            d3d_bmp->locked_rect.pBits, system_format, d3d_bmp->locked_rect.Pitch,
             0, 0, 0, 0, bitmap->lock_w, bitmap->lock_h);
       }
       al_free(bitmap->locked_region.data);
@@ -848,15 +919,34 @@ static void d3d_unlock_region(ALLEGRO_BITMAP *bitmap)
    }
    else {
       LPDIRECT3DTEXTURE9 texture;
-      if (_al_d3d_render_to_texture_supported())
+      int bitmap_format = al_get_bitmap_format(bitmap);
+      bool compressed = _al_pixel_format_is_compressed(bitmap_format);
+      if (_al_d3d_render_to_texture_supported() || compressed)
          texture = d3d_bmp->system_texture;
       else
          texture = d3d_bmp->video_texture;
       texture->UnlockRect(0);
       if (bitmap->lock_flags & ALLEGRO_LOCK_READONLY)
          return;
-      d3d_do_upload(bitmap, bitmap->lock_x, bitmap->lock_y,
-         bitmap->lock_w, bitmap->lock_h, false);
+
+      if (compressed) {
+         int block_width = al_get_pixel_block_width(bitmap_format);
+         int xc = (bitmap->lock_x / block_width) * block_width;
+         int yc = (bitmap->lock_y / block_width) * block_width;
+         int wc = _al_get_least_multiple(
+            bitmap->lock_x + bitmap->lock_w, block_width) - xc;
+         int hc = _al_get_least_multiple(
+            bitmap->lock_y + bitmap->lock_h, block_width) - yc;
+         if(!convert_compressed(
+            d3d_bmp->video_texture, d3d_bmp->system_texture,
+            xc, yc, wc, hc)) {
+            ALLEGRO_ERROR("Could not compress.\n");
+         }
+      }
+      else {
+         d3d_do_upload(bitmap, bitmap->lock_x, bitmap->lock_y,
+            bitmap->lock_w, bitmap->lock_h, false);
+      }
    }
 }
 
@@ -867,6 +957,49 @@ static void d3d_update_clipping_rectangle(ALLEGRO_BITMAP *bitmap)
 }
 
 
+static ALLEGRO_LOCKED_REGION *d3d_lock_compressed_region(
+   ALLEGRO_BITMAP *bitmap, int x, int y, int w, int h,
+   int flags)
+{
+   ALLEGRO_BITMAP_EXTRA_D3D *d3d_bmp = get_extra(bitmap);
+   int bitmap_format = al_get_bitmap_format(bitmap);
+   
+   if (d3d_bmp->display->device_lost)
+      return NULL;
+   
+   ASSERT(_al_pixel_format_is_compressed(bitmap_format));
+
+   RECT rect;
+   DWORD Flags = flags & ALLEGRO_LOCK_READONLY ? D3DLOCK_READONLY : 0;
+
+   rect.left = x;
+   rect.right = x + w;
+   rect.top = y;
+   rect.bottom = y + h;
+   
+   if (d3d_bmp->video_texture->LockRect(0, &d3d_bmp->locked_rect, &rect, Flags) != D3D_OK) {
+      ALLEGRO_ERROR("LockRect failed in d3d_lock_region.\n");
+      return NULL;
+   }
+   
+   bitmap->locked_region.data = d3d_bmp->locked_rect.pBits;
+   bitmap->locked_region.format = bitmap_format;
+   bitmap->locked_region.pitch = d3d_bmp->locked_rect.Pitch;
+   bitmap->locked_region.pixel_size = al_get_pixel_block_size(bitmap_format);
+
+   return &bitmap->locked_region;
+}
+
+
+static void d3d_unlock_compressed_region(ALLEGRO_BITMAP *bitmap)
+{
+   ALLEGRO_BITMAP_EXTRA_D3D *d3d_bmp = get_extra(bitmap);
+   ASSERT(_al_pixel_format_is_compressed(al_get_bitmap_format(bitmap)));
+
+   d3d_bmp->video_texture->UnlockRect(0);
+}
+
+
 /* Obtain a reference to this driver. */
 ALLEGRO_BITMAP_INTERFACE *_al_bitmap_d3d_driver(void)
 {
@@ -882,6 +1015,8 @@ ALLEGRO_BITMAP_INTERFACE *_al_bitmap_d3d_driver(void)
    vt->destroy_bitmap = _al_d3d_destroy_bitmap;
    vt->lock_region = d3d_lock_region;
    vt->unlock_region = d3d_unlock_region;
+   vt->lock_compressed_region = d3d_lock_compressed_region;
+   vt->unlock_compressed_region = d3d_unlock_compressed_region;
    vt->update_clipping_rectangle = d3d_update_clipping_rectangle;
 
    return vt;
diff --git a/src/win/d3d_d3dx9.cpp b/src/win/d3d_d3dx9.cpp
new file mode 100644
index 0000000..f2e7240
--- /dev/null
+++ b/src/win/d3d_d3dx9.cpp
@@ -0,0 +1,129 @@
+/*         ______   ___    ___
+ *        /\  _  \ /\_ \  /\_ \
+ *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
+ *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
+ *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
+ *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
+ *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
+ *                                           /\____/
+ *                                           \_/__/
+ *
+ *      D3DX9 DLL dynamic loading.
+ *
+ *      See LICENSE.txt for copyright information.
+ */
+
+#include "allegro5/allegro.h"
+#include "allegro5/allegro_direct3d.h"
+#include "allegro5/internal/aintern.h"
+#include "allegro5/internal/aintern_bitmap.h"
+#include "allegro5/internal/aintern_direct3d.h"
+
+#ifdef ALLEGRO_CFG_D3DX9
+
+#include <d3dx9.h>
+#include <stdio.h>
+
+#include "d3d.h"
+
+ALLEGRO_DEBUG_CHANNEL("d3dx9")
+
+// DXSDK redistributable install d3dx9_xx.dll from version
+// 24 to 43. It's unlikely that any new version will come,
+// since HLSL compiler was moved to D3DCompiler_xx.dll and
+// most recent versions of this utility library are bound
+// to DirectX 11.
+//
+// However, if any new version appears anyway, this range
+// should be changed.
+#define D3DX9_MIN_VERSION   24
+#define D3DX9_MAX_VERSION   43
+
+static HMODULE _imp_d3dx9_module = 0;
+_ALLEGRO_D3DXCREATEEFFECTPROC _al_imp_D3DXCreateEffect = NULL;
+_ALLEGRO_D3DXLSFLSPROC _al_imp_D3DXLoadSurfaceFromSurface = NULL;
+
+extern "C"
+void _al_unload_d3dx9_module()
+{
+   FreeLibrary(_imp_d3dx9_module);
+   _imp_d3dx9_module = NULL;
+}
+
+static bool _imp_load_d3dx9_module_version(int version)
+{
+   char module_name[16];
+
+   // Sanity check
+   // Comented out, to not reject choice of the user if any new version
+   // appears. See force_d3dx9_version entry in config file.
+   /*
+   if (version < 24 || version > 43) {
+      ALLEGRO_ERROR("Error: Requested version (%d) of D3DX9 library is invalid.\n", version);
+      return false;
+   }
+   */
+
+   sprintf(module_name, "d3dx9_%d.dll", version);
+
+   _imp_d3dx9_module = _al_win_safe_load_library(module_name);
+   if (NULL == _imp_d3dx9_module)
+      return false;
+
+   _al_imp_D3DXCreateEffect = (_ALLEGRO_D3DXCREATEEFFECTPROC)GetProcAddress(_imp_d3dx9_module, "D3DXCreateEffect");
+   if (NULL == _al_imp_D3DXCreateEffect) {
+      FreeLibrary(_imp_d3dx9_module);
+      _imp_d3dx9_module = NULL;
+      return false;
+   }
+
+   _al_imp_D3DXLoadSurfaceFromSurface =
+      (_ALLEGRO_D3DXLSFLSPROC)GetProcAddress(_imp_d3dx9_module, "D3DXLoadSurfaceFromSurface");
+   if (NULL == _al_imp_D3DXLoadSurfaceFromSurface) {
+      FreeLibrary(_imp_d3dx9_module);
+      _imp_d3dx9_module = NULL;
+      return false;
+   }
+
+   ALLEGRO_INFO("Module \"%s\" loaded.\n", module_name);
+
+   return true;
+}
+
+extern "C"
+bool _al_load_d3dx9_module()
+{
+   ALLEGRO_CONFIG *cfg;
+   long version;
+
+   if (_imp_d3dx9_module) {
+      return true;
+   }
+
+   cfg = al_get_system_config();
+   if (cfg) {
+      char const *value = al_get_config_value(cfg,
+         "shader", "force_d3dx9_version");
+      if (value) {
+         errno = 0;
+         version = strtol(value, NULL, 10);
+         if (errno) {
+            ALLEGRO_ERROR("Failed to override D3DX9 version. \"%s\" is not valid integer number.", value);
+            return false;
+         }
+         else
+            return _imp_load_d3dx9_module_version((int)version);
+      }
+   }
+
+   // Iterate over all valid versions.
+   for (version = D3DX9_MAX_VERSION; version >= D3DX9_MIN_VERSION; version--)
+      if (_imp_load_d3dx9_module_version((int)version))
+         return true;
+
+   ALLEGRO_ERROR("Failed to load D3DX9 library. Library is not installed.");
+
+   return false;
+}
+
+#endif
diff --git a/src/win/d3d_disp.cpp b/src/win/d3d_disp.cpp
index aa37274..0baa44b 100644
--- a/src/win/d3d_disp.cpp
+++ b/src/win/d3d_disp.cpp
@@ -82,6 +82,8 @@ static bool already_fullscreen = false; /* real fullscreen */
 static ALLEGRO_MUTEX *present_mutex;
 ALLEGRO_MUTEX *_al_d3d_lost_device_mutex;
 
+#define FOURCC(c0, c1, c2, c3) ((int)(c0) | ((int)(c1) << 8) | ((int)(c2) << 16) | ((int)(c3) << 24))
+
 /*
  * These parameters cannot be gotten by the display thread because
  * they're thread local. We get them in the calling thread first.
@@ -111,6 +113,9 @@ static int allegro_formats[] = {
    //ALLEGRO_PIXEL_FORMAT_ARGB_1555,  this format seems not to be allowed
    ALLEGRO_PIXEL_FORMAT_ABGR_F32,
    ALLEGRO_PIXEL_FORMAT_SINGLE_CHANNEL_8,
+   ALLEGRO_PIXEL_FORMAT_RGBA_DXT1,
+   ALLEGRO_PIXEL_FORMAT_RGBA_DXT3,
+   ALLEGRO_PIXEL_FORMAT_RGBA_DXT5,
    -1
 };
 
@@ -132,6 +137,9 @@ static int d3d_formats[] = {
    //D3DFMT_A1R5G5B5,
    D3DFMT_A32B32G32R32F,
    D3DFMT_L8,
+   FOURCC('D', 'X', 'T', '1'),
+   FOURCC('D', 'X', 'T', '3'),
+   FOURCC('D', 'X', 'T', '5'),
    -1
 };
 
@@ -1203,6 +1211,14 @@ static BOOL IsTextureFormatOk(D3DFORMAT TextureFormat, D3DFORMAT AdapterFormat)
    return SUCCEEDED(hr);
 }
 
+/* Same as above, but using Allegro's formats */
+static bool is_texture_format_ok(ALLEGRO_DISPLAY *display, int texture_format)
+{
+   ALLEGRO_DISPLAY_D3D *d3d_display = (ALLEGRO_DISPLAY_D3D*)display;
+   return IsTextureFormatOk((D3DFORMAT)_al_pixel_format_to_d3d(texture_format),
+      (D3DFORMAT)_al_pixel_format_to_d3d(d3d_display->format));
+}
+
 static int real_choose_bitmap_format(ALLEGRO_DISPLAY_D3D *d3d_display,
    int bits, bool alpha)
 {
@@ -1765,6 +1781,7 @@ static ALLEGRO_DISPLAY_D3D *d3d_create_display_internals(
    d3d_display->backbuffer_bmp_extra.is_backbuffer = true;
    d3d_display->backbuffer_bmp._display = al_display;
    d3d_display->backbuffer_bmp._format = _al_deduce_color_format(&al_display->extra_settings);
+   d3d_display->backbuffer_bmp._memory_format = d3d_display->backbuffer_bmp._format;
    d3d_display->backbuffer_bmp._flags = ALLEGRO_VIDEO_BITMAP;
    d3d_display->backbuffer_bmp.w = al_display->w;
    d3d_display->backbuffer_bmp.h = al_display->h;
@@ -2374,10 +2391,31 @@ static ALLEGRO_BITMAP *d3d_create_bitmap(ALLEGRO_DISPLAY *d,
    }
 
    if (_al_pixel_format_to_d3d(format) < 0) {
-      ALLEGRO_ERROR("Requested bitmap format not supported (%d).\n", format);
+      ALLEGRO_ERROR("Requested bitmap format not supported (%s).\n",
+         _al_pixel_format_name((ALLEGRO_PIXEL_FORMAT)format));
+      return NULL;
+   }
+
+   if (!is_texture_format_ok(d, format)) {
+      ALLEGRO_ERROR("Requested bitmap format not supported (%s).\n",
+         _al_pixel_format_name((ALLEGRO_PIXEL_FORMAT)format));
       return NULL;
    }
 
+   bool compressed = _al_pixel_format_is_compressed(format);
+   if (compressed) {
+      if (!_al_d3d_render_to_texture_supported()) {
+         /* Not implemented. XXX: Why not? */
+         return NULL;
+      }
+      if (!_al_imp_D3DXLoadSurfaceFromSurface) {
+         /* Need this for locking compressed bitmaps */
+         return NULL;
+      }
+   }
+   int block_width = al_get_pixel_block_width(format);
+   int block_size = al_get_pixel_block_size(format);
+
    ALLEGRO_INFO("Chose bitmap format %d\n", format);
 
    bitmap = (ALLEGRO_BITMAP *)al_malloc(sizeof *bitmap);
@@ -2385,13 +2423,14 @@ static ALLEGRO_BITMAP *d3d_create_bitmap(ALLEGRO_DISPLAY *d,
    memset(bitmap, 0, sizeof(*bitmap));
 
    bitmap->vt = _al_bitmap_d3d_driver();
-   bitmap->memory = NULL;
    bitmap->_format = format;
    bitmap->_flags = flags;
-   bitmap->pitch = w * al_get_pixel_size(format);
    al_identity_transform(&bitmap->transform);
 
-   bitmap->memory = (unsigned char *)al_malloc(bitmap->pitch * h);
+   bitmap->pitch =
+      _al_get_least_multiple(w, block_width) / block_width * block_size;
+   bitmap->memory = (unsigned char *)al_malloc(
+      bitmap->pitch * _al_get_least_multiple(h, block_width) / block_width);
 
    extra = (ALLEGRO_BITMAP_EXTRA_D3D *)al_calloc(1, sizeof *extra);
    bitmap->extra = extra;
@@ -2400,6 +2439,7 @@ static ALLEGRO_BITMAP *d3d_create_bitmap(ALLEGRO_DISPLAY *d,
    extra->initialized = false;
    extra->is_backbuffer = false;
    extra->render_target = NULL;
+   extra->system_format = compressed ? ALLEGRO_PIXEL_FORMAT_ARGB_8888 : format;
 
    extra->display = (ALLEGRO_DISPLAY_D3D *)d;
 
diff --git a/src/win/d3d_shader.cpp b/src/win/d3d_shader.cpp
index be64819..98829e7 100644
--- a/src/win/d3d_shader.cpp
+++ b/src/win/d3d_shader.cpp
@@ -40,26 +40,6 @@ struct ALLEGRO_SHADER_HLSL_S
    LPD3DXEFFECT hlsl_shader;
 };
 
-
-// DXSDK redistributable install d3dx9_xx.dll from version
-// 24 to 43. It's unlikely that any new version will come,
-// since HLSL compiler was moved to D3DCompiler_xx.dll and
-// most recent versions of this utility library are bound
-// to DirectX 11.
-//
-// However, if any new version appears anyway, this range
-// should be changed.
-#define D3DX9_MIN_VERSION   24
-#define D3DX9_MAX_VERSION   43
-
-typedef HRESULT (WINAPI *D3DXCREATEEFFECTPROC)(LPDIRECT3DDEVICE9, LPCVOID, UINT,
-   CONST D3DXMACRO*, LPD3DXINCLUDE, DWORD, LPD3DXEFFECTPOOL, LPD3DXEFFECT*,
-   LPD3DXBUFFER*);
-
-static HMODULE _imp_d3dx9_module = 0;
-static D3DXCREATEEFFECTPROC _imp_D3DXCreateEffect = NULL;
-
-
 static const char *null_source = "";
 
 static const char *technique_source_vertex =
@@ -92,81 +72,6 @@ static const char *technique_source_both =
    "   }\n"
    "}\n";
 
-extern "C"
-void _al_unload_d3dx9_module()
-{
-   FreeLibrary(_imp_d3dx9_module);
-   _imp_d3dx9_module = NULL;
-}
-
-static bool _imp_load_d3dx9_module_version(int version)
-{
-   char module_name[16];
-
-   // Sanity check
-   // Comented out, to not reject choice of the user if any new version
-   // appears. See force_d3dx9_version entry in config file.
-   /*
-   if (version < 24 || version > 43) {
-      ALLEGRO_ERROR("Error: Requested version (%d) of D3DX9 library is invalid.\n", version);
-      return false;
-   }
-   */
-
-   sprintf(module_name, "d3dx9_%d.dll", version);
-
-   _imp_d3dx9_module = _al_win_safe_load_library(module_name);
-   if (NULL == _imp_d3dx9_module)
-      return false;
-
-   _imp_D3DXCreateEffect = (D3DXCREATEEFFECTPROC)GetProcAddress(_imp_d3dx9_module, "D3DXCreateEffect");
-   if (NULL == _imp_D3DXCreateEffect) {
-      FreeLibrary(_imp_d3dx9_module);
-      _imp_d3dx9_module = NULL;
-      return false;
-   }
-
-   ALLEGRO_INFO("Module \"%s\" loaded.\n", module_name);
-
-   return true;
-}
-
-extern "C"
-bool _al_load_d3dx9_module()
-{
-   ALLEGRO_CONFIG *cfg;
-   long version;
-
-   if (_imp_d3dx9_module) {
-      return true;
-   }
-
-   cfg = al_get_system_config();
-   if (cfg) {
-      char const *value = al_get_config_value(cfg,
-         "shader", "force_d3dx9_version");
-      if (value) {
-         errno = 0;
-         version = strtol(value, NULL, 10);
-         if (errno) {
-            ALLEGRO_ERROR("Failed to override D3DX9 version. \"%s\" is not valid integer number.", value);
-            return false;
-         }
-         else
-            return _imp_load_d3dx9_module_version((int)version);
-      }
-   }
-
-   // Iterate over all valid versions.
-   for (version = D3DX9_MAX_VERSION; version >= D3DX9_MIN_VERSION; version--)
-      if (_imp_load_d3dx9_module_version((int)version))
-         return true;
-
-   ALLEGRO_ERROR("Failed to load D3DX9 library. Library is not installed.");
-
-   return false;
-}
-
 
 static bool hlsl_attach_shader_source(ALLEGRO_SHADER *shader,
                ALLEGRO_SHADER_TYPE type, const char *source);
@@ -236,7 +141,7 @@ ALLEGRO_SHADER *_al_create_shader_hlsl(ALLEGRO_SHADER_PLATFORM platform)
 {
    ALLEGRO_SHADER_HLSL_S *shader;
 
-   if (NULL == _imp_D3DXCreateEffect) {
+   if (NULL == _al_imp_D3DXCreateEffect) {
       ALLEGRO_ERROR("D3DXCreateEffect unavailable\n");
       return NULL;
    }
@@ -334,7 +239,7 @@ static bool hlsl_attach_shader_source(ALLEGRO_SHADER *shader,
    full_source = al_ustr_newf("%s\n#line 1\n%s\n%s\n",
       vertex_source, pixel_source, technique_source);
 
-   DWORD ok = _imp_D3DXCreateEffect(
+   DWORD ok = _al_imp_D3DXCreateEffect(
       al_get_d3d_device(display),
       al_cstr(full_source),
       al_ustr_size(full_source),


Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/