Example #1
0
void buzzer_callback()
{
	/* Start by incrementing the counter; we are playing the next note
	 * This is here because the index must atually point to the note
	 * currently playing, so main knows if we can go to LPM3 */
	buzzer_counter++;

	/* Here the -1 is needed for the offset of buzzer_counter due to the
	 * increment above. */
	note n = *(buzzer_buffer + buzzer_counter - 1);
	/* 0x000F is the "stop bit" */
	if(PITCH(n) == 0) {
		/* Stop buzzer */
		buzzer_stop();
		return;
	}
	if (PITCH(n) == 0x000F) {
		/* Stop the timer! We are playing a rest */
		TA1CTL &= ~MC_3;
	} else {
		/* Set PWM frequency */
		TA1CCR0 = base_notes[PITCH(n)] >> OCTAVE(n);

		/* Start the timer */
		TA1CTL |= MC__UP;
	}

	/* Delay for DURATION(*n) milliseconds, */
	timer0_delay_callback(DURATION(n), &buzzer_callback);
}
Example #2
0
void buzzer_play(note *notes)
{

	/* Allow buzzer PWM output on P2.7 */
	P2SEL |= BIT7;

	/* 0x000F is the "stop bit" */
	while (PITCH(*notes) != 0x000F) {
		if (PITCH(*notes) == 0) {
			/* Stop the timer! We are playing a rest */
			TA1CTL &= ~MC_3;
		} else {
			/* Set PWM frequency */
			TA1CCR0 = base_notes[PITCH(*notes)] >> OCTAVE(*notes);

			/* Start the timer */
			TA1CTL |= MC__UP;
		}

		/* Delay for DURATION(*notes) milliseconds,
		   use LPM1 because we need SMCLK for tone generation */
		timer0_delay(DURATION(*notes), LPM1_bits);

		/* Advance to the next note */
		notes++;
	}

	/* Stop buzzer */
	buzzer_stop();
}
Example #3
0
void I_UpdateSoundParams(int channel, int vol, int sep, int pitch)
{
// proff 07/04/98: Added for CYGWIN32 compatibility
#ifdef HAVE_LIBDSOUND

  int DSB_Status;
  if (noDSound == true)
    return;

// proff 07/26/98: Added volume check
  if (vol==0)
    {
      IDirectSoundBuffer_Stop(lpSecondaryDSB[channel]);
      return;
    }
  IDirectSoundBuffer_SetVolume(lpSecondaryDSB[channel],VOL(vol));
  IDirectSoundBuffer_SetPan(lpSecondaryDSB[channel],SEP(sep));
  IDirectSoundBuffer_SetFrequency
    (lpSecondaryDSB[channel], ChannelInfo[channel].samplerate+PITCH(pitch));
  if (ChannelInfo[channel].playing == true)
    {
      IDirectSoundBuffer_GetStatus(lpSecondaryDSB[channel], &DSB_Status);
      if ((DSB_Status & DSBSTATUS_PLAYING) == 0)
	IDirectSoundBuffer_Play(lpSecondaryDSB[channel], 0, 0, 0);
    }
#endif // HAVE_LIBDSOUND
}
Example #4
0
void sna_read_boxes(struct sna *sna, PixmapPtr dst, struct kgem_bo *src_bo,
		    const BoxRec *box, int nbox)
{
	struct kgem *kgem = &sna->kgem;
	struct kgem_bo *dst_bo;
	BoxRec extents;
	const BoxRec *tmp_box;
	int tmp_nbox;
	void *ptr;
	int src_pitch, cpp, offset;
	int n, cmd, br13;
	bool can_blt;

	DBG(("%s x %d, src=(handle=%d), dst=(size=(%d, %d)\n",
	     __FUNCTION__, nbox, src_bo->handle,
	     dst->drawable.width, dst->drawable.height));

#ifndef NDEBUG
	for (n = 0; n < nbox; n++) {
		if (box[n].x1 < 0 || box[n].y1 < 0 ||
		    box[n].x2 * dst->drawable.bitsPerPixel/8 > src_bo->pitch ||
		    box[n].y2 * src_bo->pitch > kgem_bo_size(src_bo))
		{
			FatalError("source out-of-bounds box[%d]=(%d, %d), (%d, %d), pitch=%d, size=%d\n", n,
				   box[n].x1, box[n].y1,
				   box[n].x2, box[n].y2,
				   src_bo->pitch, kgem_bo_size(src_bo));
		}
	}
#endif

	/* XXX The gpu is faster to perform detiling in bulk, but takes
	 * longer to setup and retrieve the results, with an additional
	 * copy. The long term solution is to use snoopable bo and avoid
	 * this path.
	 */

	if (download_inplace(kgem, dst, src_bo, box ,nbox)) {
fallback:
		read_boxes_inplace(kgem, dst, src_bo, box, nbox);
		return;
	}

	can_blt = kgem_bo_can_blt(kgem, src_bo) &&
		(box[0].x2 - box[0].x1) * dst->drawable.bitsPerPixel < 8 * (MAXSHORT - 4);
	extents = box[0];
	for (n = 1; n < nbox; n++) {
		if (box[n].x1 < extents.x1)
			extents.x1 = box[n].x1;
		if (box[n].x2 > extents.x2)
			extents.x2 = box[n].x2;

		if (can_blt)
			can_blt = (box[n].x2 - box[n].x1) * dst->drawable.bitsPerPixel < 8 * (MAXSHORT - 4);

		if (box[n].y1 < extents.y1)
			extents.y1 = box[n].y1;
		if (box[n].y2 > extents.y2)
			extents.y2 = box[n].y2;
	}
	if (kgem_bo_can_map(kgem, src_bo)) {
		/* Is it worth detiling? */
		if ((extents.y2 - extents.y1 - 1) * src_bo->pitch < 4096)
			goto fallback;
	}

	/* Try to avoid switching rings... */
	if (!can_blt || kgem->ring == KGEM_RENDER ||
	    upload_too_large(sna, extents.x2 - extents.x1, extents.y2 - extents.y1)) {
		PixmapRec tmp;

		tmp.drawable.width  = extents.x2 - extents.x1;
		tmp.drawable.height = extents.y2 - extents.y1;
		tmp.drawable.depth  = dst->drawable.depth;
		tmp.drawable.bitsPerPixel = dst->drawable.bitsPerPixel;
		tmp.devPrivate.ptr = NULL;

		assert(tmp.drawable.width);
		assert(tmp.drawable.height);

		if (must_tile(sna, tmp.drawable.width, tmp.drawable.height)) {
			BoxRec tile, stack[64], *clipped, *c;
			int step;

			if (n > ARRAY_SIZE(stack)) {
				clipped = malloc(sizeof(BoxRec) * n);
				if (clipped == NULL)
					goto fallback;
			} else
				clipped = stack;

			step = MIN(sna->render.max_3d_size,
				   8*(MAXSHORT&~63) / dst->drawable.bitsPerPixel);
			while (step * step * 4 > sna->kgem.max_upload_tile_size)
				step /= 2;

			DBG(("%s: tiling download, using %dx%d tiles\n",
			     __FUNCTION__, step, step));
			assert(step);

			for (tile.y1 = extents.y1; tile.y1 < extents.y2; tile.y1 = tile.y2) {
				int y2 = tile.y1 + step;
				if (y2 > extents.y2)
					y2 = extents.y2;
				tile.y2 = y2;

				for (tile.x1 = extents.x1; tile.x1 < extents.x2; tile.x1 = tile.x2) {
					int x2 = tile.x1 + step;
					if (x2 > extents.x2)
						x2 = extents.x2;
					tile.x2 = x2;

					tmp.drawable.width  = tile.x2 - tile.x1;
					tmp.drawable.height = tile.y2 - tile.y1;

					c = clipped;
					for (n = 0; n < nbox; n++) {
						*c = box[n];
						if (!box_intersect(c, &tile))
							continue;

						DBG(("%s: box(%d, %d), (%d, %d),, dst=(%d, %d)\n",
						     __FUNCTION__,
						     c->x1, c->y1,
						     c->x2, c->y2,
						     c->x1 - tile.x1,
						     c->y1 - tile.y1));
						c++;
					}
					if (c == clipped)
						continue;

					dst_bo = kgem_create_buffer_2d(kgem,
								       tmp.drawable.width,
								       tmp.drawable.height,
								       tmp.drawable.bitsPerPixel,
								       KGEM_BUFFER_LAST,
								       &ptr);
					if (!dst_bo) {
						if (clipped != stack)
							free(clipped);
						goto fallback;
					}

					if (!sna->render.copy_boxes(sna, GXcopy,
								    dst, src_bo, 0, 0,
								    &tmp, dst_bo, -tile.x1, -tile.y1,
								    clipped, c-clipped, COPY_LAST)) {
						kgem_bo_destroy(&sna->kgem, dst_bo);
						if (clipped != stack)
							free(clipped);
						goto fallback;
					}

					kgem_bo_submit(&sna->kgem, dst_bo);
					kgem_buffer_read_sync(kgem, dst_bo);

					if (sigtrap_get() == 0) {
						while (c-- != clipped) {
							memcpy_blt(ptr, dst->devPrivate.ptr, tmp.drawable.bitsPerPixel,
								   dst_bo->pitch, dst->devKind,
								   c->x1 - tile.x1,
								   c->y1 - tile.y1,
								   c->x1, c->y1,
								   c->x2 - c->x1,
								   c->y2 - c->y1);
						}
						sigtrap_put();
					}

					kgem_bo_destroy(&sna->kgem, dst_bo);
				}
			}

			if (clipped != stack)
				free(clipped);
		} else {
			dst_bo = kgem_create_buffer_2d(kgem,
						       tmp.drawable.width,
						       tmp.drawable.height,
						       tmp.drawable.bitsPerPixel,
						       KGEM_BUFFER_LAST,
						       &ptr);
			if (!dst_bo)
				goto fallback;

			if (!sna->render.copy_boxes(sna, GXcopy,
						    dst, src_bo, 0, 0,
						    &tmp, dst_bo, -extents.x1, -extents.y1,
						    box, nbox, COPY_LAST)) {
				kgem_bo_destroy(&sna->kgem, dst_bo);
				goto fallback;
			}

			kgem_bo_submit(&sna->kgem, dst_bo);
			kgem_buffer_read_sync(kgem, dst_bo);

			if (sigtrap_get() == 0) {
				for (n = 0; n < nbox; n++) {
					memcpy_blt(ptr, dst->devPrivate.ptr, tmp.drawable.bitsPerPixel,
						   dst_bo->pitch, dst->devKind,
						   box[n].x1 - extents.x1,
						   box[n].y1 - extents.y1,
						   box[n].x1, box[n].y1,
						   box[n].x2 - box[n].x1,
						   box[n].y2 - box[n].y1);
				}
				sigtrap_put();
			}

			kgem_bo_destroy(&sna->kgem, dst_bo);
		}
		return;
	}

	/* count the total number of bytes to be read and allocate a bo */
	cpp = dst->drawable.bitsPerPixel / 8;
	offset = 0;
	for (n = 0; n < nbox; n++) {
		int height = box[n].y2 - box[n].y1;
		int width = box[n].x2 - box[n].x1;
		offset += PITCH(width, cpp) * height;
	}

	DBG(("    read buffer size=%d\n", offset));

	dst_bo = kgem_create_buffer(kgem, offset, KGEM_BUFFER_LAST, &ptr);
	if (!dst_bo) {
		read_boxes_inplace(kgem, dst, src_bo, box, nbox);
		return;
	}

	cmd = XY_SRC_COPY_BLT_CMD;
	src_pitch = src_bo->pitch;
	if (kgem->gen >= 040 && src_bo->tiling) {
		cmd |= BLT_SRC_TILED;
		src_pitch >>= 2;
	}
Example #5
0
int I_StartSound(sfxinfo_t *sound, int vol, int sep, int pitch, int pri)
{
  int channel=0;

  // proff 07/04/98: Added for CYGWIN32 compatibility
#ifdef HAVE_LIBDSOUND
  HRESULT error;
  char *snddata;
  int sndlength;

  if (noDSound == true)
    return channel;

  // load sound data if we have not already  

  I_CacheSound(sound);

  // find a free channel

  channel = I_GetFreeChannel();

  // proff 07/26/98: Added volume check
  // proff 10/31/98: Added Stop before updating sound-data

  error = IDirectSoundBuffer_Stop(lpSecondaryDSB[channel]);
  ChannelInfo[channel].playing = false;
  
  if (vol==0)
    return channel;

  snddata = sound->data;

  ChannelInfo[channel].samplerate = (snddata[3] << 8) + snddata[2];
// proff 10/31/98: Use accurate time for this one
  ChannelInfo[channel].endtime = 
    I_GetTime_RealTime() + 
    (sound->length * 35) / ChannelInfo[channel].samplerate + 1;

  // skip past header

  snddata += 8;
  sndlength = sound->length - 8;

  error = IDirectSoundBuffer_SetCurrentPosition(lpSecondaryDSB[channel],0);

  // proff 11/09/98: Added for a slight speedup
  if (sound != ChannelInfo[channel].sfx)
    {
      DWORD *hand1,*hand2;
      DWORD len1,len2;

      ChannelInfo[channel].sfx = sound;
      error = IDirectSoundBuffer_Lock(lpSecondaryDSB[channel],0,65535,
				      &hand1,&len1,&hand2,&len2,
				      DSBLOCK_FROMWRITECURSOR);
      if (len1 >= sndlength) 
	{
	  memset(hand1, 128, len1);
	  memcpy(hand1, snddata , sndlength);
	  memset(hand2, 128, len2);
	}
      else 
	{
	  memcpy(hand1, snddata, len1);
	  memcpy(hand2, &((char *)snddata)[len1], sndlength-len1);
	}
      
      error = IDirectSoundBuffer_Unlock
	(lpSecondaryDSB[channel], hand1, len1, hand2, len2);
    }
  IDirectSoundBuffer_SetVolume(lpSecondaryDSB[channel], VOL(vol));
  IDirectSoundBuffer_SetPan(lpSecondaryDSB[channel], SEP(sep));
  IDirectSoundBuffer_SetFrequency(lpSecondaryDSB[channel], 
				  ChannelInfo[channel].samplerate+PITCH(pitch));
  error = IDirectSoundBuffer_Play(lpSecondaryDSB[channel], 0, 0, 0);
  ChannelInfo[channel].playing = true;

#endif // HAVE_LIBDSOUND
  return channel;
}
Example #6
0
bool GLDriver::checkActiveTextures()
{
   std::vector<uint8_t> untiledImage, untiledMipmap;
   gx2::GX2Surface surface;

   for (auto i = 0; i < latte::MaxTextures; ++i) {
      auto resourceOffset = (latte::SQ_PS_TEX_RESOURCE_0 + i) * 7;
      auto sq_tex_resource_word0 = getRegister<latte::SQ_TEX_RESOURCE_WORD0_N>(latte::Register::SQ_TEX_RESOURCE_WORD0_0 + 4 * resourceOffset);
      auto sq_tex_resource_word1 = getRegister<latte::SQ_TEX_RESOURCE_WORD1_N>(latte::Register::SQ_TEX_RESOURCE_WORD1_0 + 4 * resourceOffset);
      auto sq_tex_resource_word2 = getRegister<latte::SQ_TEX_RESOURCE_WORD2_N>(latte::Register::SQ_TEX_RESOURCE_WORD2_0 + 4 * resourceOffset);
      auto sq_tex_resource_word3 = getRegister<latte::SQ_TEX_RESOURCE_WORD3_N>(latte::Register::SQ_TEX_RESOURCE_WORD3_0 + 4 * resourceOffset);
      auto sq_tex_resource_word4 = getRegister<latte::SQ_TEX_RESOURCE_WORD4_N>(latte::Register::SQ_TEX_RESOURCE_WORD4_0 + 4 * resourceOffset);
      auto sq_tex_resource_word5 = getRegister<latte::SQ_TEX_RESOURCE_WORD5_N>(latte::Register::SQ_TEX_RESOURCE_WORD5_0 + 4 * resourceOffset);
      auto sq_tex_resource_word6 = getRegister<latte::SQ_TEX_RESOURCE_WORD6_N>(latte::Register::SQ_TEX_RESOURCE_WORD6_0 + 4 * resourceOffset);
      auto baseAddress = sq_tex_resource_word2.BASE_ADDRESS() << 8;

      if (!baseAddress) {
         continue;
      }

      if (baseAddress == mPixelTextureCache[i].baseAddress
       && sq_tex_resource_word0.value == mPixelTextureCache[i].word0
       && sq_tex_resource_word1.value == mPixelTextureCache[i].word1
       && sq_tex_resource_word2.value == mPixelTextureCache[i].word2
       && sq_tex_resource_word3.value == mPixelTextureCache[i].word3
       && sq_tex_resource_word4.value == mPixelTextureCache[i].word4
       && sq_tex_resource_word5.value == mPixelTextureCache[i].word5
       && sq_tex_resource_word6.value == mPixelTextureCache[i].word6) {
         continue;  // No change in sampler state
      }

      mPixelTextureCache[i].baseAddress = baseAddress;
      mPixelTextureCache[i].word0 = sq_tex_resource_word0.value;
      mPixelTextureCache[i].word1 = sq_tex_resource_word1.value;
      mPixelTextureCache[i].word2 = sq_tex_resource_word2.value;
      mPixelTextureCache[i].word3 = sq_tex_resource_word3.value;
      mPixelTextureCache[i].word4 = sq_tex_resource_word4.value;
      mPixelTextureCache[i].word5 = sq_tex_resource_word5.value;
      mPixelTextureCache[i].word6 = sq_tex_resource_word6.value;

      // Decode resource registers
      auto pitch = (sq_tex_resource_word0.PITCH() + 1) * 8;
      auto width = sq_tex_resource_word0.TEX_WIDTH() + 1;
      auto height = sq_tex_resource_word1.TEX_HEIGHT() + 1;
      auto depth = sq_tex_resource_word1.TEX_DEPTH() + 1;

      auto format = sq_tex_resource_word1.DATA_FORMAT();
      auto tileMode = sq_tex_resource_word0.TILE_MODE();
      auto numFormat = sq_tex_resource_word4.NUM_FORMAT_ALL();
      auto formatComp = sq_tex_resource_word4.FORMAT_COMP_X();
      auto degamma = sq_tex_resource_word4.FORCE_DEGAMMA();
      auto dim = sq_tex_resource_word0.DIM();

      auto buffer = getSurfaceBuffer(baseAddress, width, height, depth, dim, format, numFormat, formatComp, degamma, sq_tex_resource_word0.TILE_TYPE());

      if (buffer->dirtyAsTexture) {
         auto swizzle = sq_tex_resource_word2.SWIZZLE() << 8;

         // Rebuild a GX2Surface
         std::memset(&surface, 0, sizeof(gx2::GX2Surface));

         surface.dim = static_cast<gx2::GX2SurfaceDim>(dim);
         surface.width = width;
         surface.height = height;

         if (surface.dim == gx2::GX2SurfaceDim::TextureCube) {
            surface.depth = depth * 6;
         } else if (surface.dim == gx2::GX2SurfaceDim::Texture3D ||
            surface.dim == gx2::GX2SurfaceDim::Texture2DMSAAArray ||
            surface.dim == gx2::GX2SurfaceDim::Texture2DArray ||
            surface.dim == gx2::GX2SurfaceDim::Texture1DArray) {
            surface.depth = depth;
         } else {
            surface.depth = 1;
         }

         surface.mipLevels = 1;
         surface.format = getSurfaceFormat(format, numFormat, formatComp, degamma);

         surface.aa = gx2::GX2AAMode::Mode1X;
         surface.use = gx2::GX2SurfaceUse::Texture;

         if (sq_tex_resource_word0.TILE_TYPE()) {
            surface.use |= gx2::GX2SurfaceUse::DepthBuffer;
         }

         surface.tileMode = static_cast<gx2::GX2TileMode>(tileMode);
         surface.swizzle = swizzle;

         // Update the sizing information for the surface
         GX2CalcSurfaceSizeAndAlignment(&surface);

         // Align address
         baseAddress &= ~(surface.alignment - 1);

         surface.image = make_virtual_ptr<uint8_t>(baseAddress);
         surface.mipmaps = nullptr;

         // Calculate a new memory CRC
         uint64_t newHash[2] = { 0 };
         MurmurHash3_x64_128(surface.image, surface.imageSize, 0, newHash);

         // If the CPU memory has changed, we should re-upload this.  This hashing is
         //  also means that if the application temporarily uses one of its buffers as
         //  a color buffer, we are able to accurately handle this.  Providing they are
         //  not updating the memory at the same time.
         if (newHash[0] != buffer->cpuMemHash[0] || newHash[1] != buffer->cpuMemHash[1]) {
            buffer->cpuMemHash[0] = newHash[0];
            buffer->cpuMemHash[1] = newHash[1];

            // Untile
            gx2::internal::convertTiling(&surface, untiledImage, untiledMipmap);

            // Create texture
            auto compressed = isCompressedFormat(format);
            auto target = getTextureTarget(dim);
            auto textureDataType = gl::GL_INVALID_ENUM;
            auto textureFormat = getTextureFormat(format);
            auto size = untiledImage.size();

            if (compressed) {
               textureDataType = getCompressedTextureDataType(format, degamma);
            } else {
               textureDataType = getTextureDataType(format, formatComp);
            }

            if (textureDataType == gl::GL_INVALID_ENUM || textureFormat == gl::GL_INVALID_ENUM) {
               decaf_abort(fmt::format("Texture with unsupported format {}", surface.format.value()));
            }

            switch (dim) {
            case latte::SQ_TEX_DIM_1D:
               if (compressed) {
                  gl::glCompressedTextureSubImage1D(buffer->object,
                                                    0, /* level */
                                                    0, /* xoffset */
                                                    width,
                                                    textureDataType,
                                                    gsl::narrow_cast<gl::GLsizei>(size),
                                                    untiledImage.data());
               } else {
                  gl::glTextureSubImage1D(buffer->object,
                                          0, /* level */
                                          0, /* xoffset */
                                          width,
                                          textureFormat,
                                          textureDataType,
                                          untiledImage.data());
               }
               break;
            case latte::SQ_TEX_DIM_2D:
               if (compressed) {
                  gl::glCompressedTextureSubImage2D(buffer->object,
                                                    0, /* level */
                                                    0, 0, /* xoffset, yoffset */
                                                    width,
                                                    height,
                                                    textureDataType,
                                                    gsl::narrow_cast<gl::GLsizei>(size),
                                                    untiledImage.data());
               } else {
                  gl::glTextureSubImage2D(buffer->object,
                                          0, /* level */
                                          0, 0, /* xoffset, yoffset */
                                          width, height,
                                          textureFormat,
                                          textureDataType,
                                          untiledImage.data());
               }
               break;
            case latte::SQ_TEX_DIM_3D:
               if (compressed) {
                  gl::glCompressedTextureSubImage3D(buffer->object,
                                                    0, /* level */
                                                    0, 0, 0, /* xoffset, yoffset, zoffset */
                                                    width, height, depth,
                                                    textureDataType,
                                                    gsl::narrow_cast<gl::GLsizei>(size),
                                                    untiledImage.data());
               } else {
                  gl::glTextureSubImage3D(buffer->object,
                                          0, /* level */
                                          0, 0, 0, /* xoffset, yoffset, zoffset */
                                          width, height, depth,
                                          textureFormat,
                                          textureDataType,
                                          untiledImage.data());
               }
               break;
            case latte::SQ_TEX_DIM_CUBEMAP:
               decaf_check(surface.depth == 6);
            case latte::SQ_TEX_DIM_2D_ARRAY:
               if (compressed) {
                  gl::glCompressedTextureSubImage3D(buffer->object,
                                                    0, /* level */
                                                    0, 0, 0, /* xoffset, yoffset, zoffset */
                                                    width, height, surface.depth,
                                                    textureDataType,
                                                    gsl::narrow_cast<gl::GLsizei>(size),
                                                    untiledImage.data());
               } else {
                  gl::glTextureSubImage3D(buffer->object,
                                          0, /* level */
                                          0, 0, 0, /* xoffset, yoffset, zoffset */
                                          width, height, surface.depth,
                                          textureFormat,
                                          textureDataType,
                                          untiledImage.data());
               }
               break;
            default:
               decaf_abort(fmt::format("Unsupported texture dim: {}", sq_tex_resource_word0.DIM()));
            }
         }

         buffer->dirtyAsTexture = false;
         buffer->state = SurfaceUseState::CpuWritten;
      }

      // Setup texture swizzle
      auto dst_sel_x = getTextureSwizzle(sq_tex_resource_word4.DST_SEL_X());
      auto dst_sel_y = getTextureSwizzle(sq_tex_resource_word4.DST_SEL_Y());
      auto dst_sel_z = getTextureSwizzle(sq_tex_resource_word4.DST_SEL_Z());
      auto dst_sel_w = getTextureSwizzle(sq_tex_resource_word4.DST_SEL_W());

      gl::GLint textureSwizzle[] = {
         static_cast<gl::GLint>(dst_sel_x),
         static_cast<gl::GLint>(dst_sel_y),
         static_cast<gl::GLint>(dst_sel_z),
         static_cast<gl::GLint>(dst_sel_w),
      };

      gl::glTextureParameteriv(buffer->object, gl::GL_TEXTURE_SWIZZLE_RGBA, textureSwizzle);
      gl::glBindTextureUnit(i, buffer->object);
   }

   return true;
}